Reactos
1/*
2 * PROJECT: ReactOS CTF
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: ITfInputProcessorProfiles implementation
5 * COPYRIGHT: Copyright 2009 Aric Stewart, CodeWeavers
6 * Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7 */
8
9#include "precomp.h"
10
11#include <wine/debug.h>
12WINE_DEFAULT_DEBUG_CHANNEL(msctf);
13
14////////////////////////////////////////////////////////////////////////////
15
16class CInputProcessorProfiles
17 : public ITfInputProcessorProfiles
18 , public ITfSource
19 , public ITfInputProcessorProfileMgr
20 // , public ITfInputProcessorProfilesEx
21 // , public ITfInputProcessorProfileSubstituteLayout
22{
23public:
24 CInputProcessorProfiles();
25 virtual ~CInputProcessorProfiles();
26
27 static HRESULT CreateInstance(IUnknown *pUnkOuter, CInputProcessorProfiles **ppOut);
28
29 // ** IUnknown methods **
30 STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObj) override;
31 STDMETHODIMP_(ULONG) AddRef() override;
32 STDMETHODIMP_(ULONG) Release() override;
33
34 // ** ITfInputProcessorProfiles methods **
35 STDMETHODIMP Register(_In_ REFCLSID rclsid) override;
36 STDMETHODIMP Unregister(_In_ REFCLSID rclsid) override;
37 STDMETHODIMP AddLanguageProfile(
38 _In_ REFCLSID rclsid,
39 _In_ LANGID langid,
40 _In_ REFGUID guidProfile,
41 _In_ const WCHAR *pchDesc,
42 _In_ ULONG cchDesc,
43 _In_ const WCHAR *pchIconFile,
44 _In_ ULONG cchFile,
45 _In_ ULONG uIconIndex) override;
46 STDMETHODIMP RemoveLanguageProfile(
47 _In_ REFCLSID rclsid,
48 _In_ LANGID langid,
49 _In_ REFGUID guidProfile) override;
50 STDMETHODIMP EnumInputProcessorInfo(_Out_ IEnumGUID **ppEnum) override;
51 STDMETHODIMP GetDefaultLanguageProfile(
52 _In_ LANGID langid,
53 _In_ REFGUID catid,
54 _Out_ CLSID *pclsid,
55 _Out_ GUID *pguidProfile) override;
56 STDMETHODIMP SetDefaultLanguageProfile(
57 _In_ LANGID langid,
58 _In_ REFCLSID rclsid,
59 _In_ REFGUID guidProfiles) override;
60 STDMETHODIMP ActivateLanguageProfile(
61 _In_ REFCLSID rclsid,
62 _In_ LANGID langid,
63 _In_ REFGUID guidProfiles) override;
64 STDMETHODIMP GetActiveLanguageProfile(
65 _In_ REFCLSID rclsid,
66 _Out_ LANGID *plangid,
67 _Out_ GUID *pguidProfile) override;
68 STDMETHODIMP GetLanguageProfileDescription(
69 _In_ REFCLSID rclsid,
70 _In_ LANGID langid,
71 _In_ REFGUID guidProfile,
72 _Out_ BSTR *pbstrProfile) override;
73 STDMETHODIMP GetCurrentLanguage(_Out_ LANGID *plangid) override;
74 STDMETHODIMP ChangeCurrentLanguage(_In_ LANGID langid) override;
75 STDMETHODIMP GetLanguageList(
76 _Out_ LANGID **ppLangId,
77 _Out_ ULONG *pulCount) override;
78 STDMETHODIMP EnumLanguageProfiles(
79 _In_ LANGID langid,
80 _Out_ IEnumTfLanguageProfiles **ppEnum) override;
81 STDMETHODIMP EnableLanguageProfile(
82 _In_ REFCLSID rclsid,
83 _In_ LANGID langid,
84 _In_ REFGUID guidProfile,
85 _In_ BOOL fEnable) override;
86 STDMETHODIMP IsEnabledLanguageProfile(
87 _In_ REFCLSID rclsid,
88 _In_ LANGID langid,
89 _In_ REFGUID guidProfile,
90 _Out_ BOOL *pfEnable) override;
91 STDMETHODIMP EnableLanguageProfileByDefault(
92 _In_ REFCLSID rclsid,
93 _In_ LANGID langid,
94 _In_ REFGUID guidProfile,
95 _In_ BOOL fEnable) override;
96 STDMETHODIMP SubstituteKeyboardLayout(
97 _In_ REFCLSID rclsid,
98 _In_ LANGID langid,
99 _In_ REFGUID guidProfile,
100 _In_ HKL hKL) override;
101
102 // ** ITfSource methods **
103 STDMETHODIMP AdviseSink(
104 _In_ REFIID riid,
105 _In_ IUnknown *punk,
106 _Out_ DWORD *pdwCookie) override;
107 STDMETHODIMP UnadviseSink(_In_ DWORD dwCookie) override;
108
109 // ** ITfInputProcessorProfileMgr methods **
110 STDMETHODIMP ActivateProfile(
111 _In_ DWORD dwProfileType,
112 _In_ LANGID langid,
113 _In_ REFCLSID clsid,
114 _In_ REFGUID guidProfile,
115 _In_ HKL hkl,
116 _In_ DWORD dwFlags) override;
117 STDMETHODIMP DeactivateProfile(
118 _In_ DWORD dwProfileType,
119 _In_ LANGID langid,
120 _In_ REFCLSID clsid,
121 _In_ REFGUID guidProfile,
122 _In_ HKL hkl,
123 _In_ DWORD dwFlags) override;
124 STDMETHODIMP GetProfile(
125 _In_ DWORD dwProfileType,
126 _In_ LANGID langid,
127 _In_ REFCLSID clsid,
128 _In_ REFGUID guidProfile,
129 _In_ HKL hkl,
130 _Out_ TF_INPUTPROCESSORPROFILE *pProfile) override;
131 STDMETHODIMP EnumProfiles(
132 _In_ LANGID langid,
133 _Out_ IEnumTfInputProcessorProfiles **ppEnum) override;
134 STDMETHODIMP ReleaseInputProcessor(
135 _In_ REFCLSID rclsid,
136 _In_ DWORD dwFlags) override;
137 STDMETHODIMP RegisterProfile(
138 _In_ REFCLSID rclsid,
139 _In_ LANGID langid,
140 _In_ REFGUID guidProfile,
141 _In_ const WCHAR *pchDesc,
142 _In_ ULONG cchDesc,
143 _In_ const WCHAR *pchIconFile,
144 _In_ ULONG cchFile,
145 _In_ ULONG uIconIndex,
146 _In_ HKL hklsubstitute,
147 _In_ DWORD dwPreferredLayout,
148 _In_ BOOL bEnabledByDefault,
149 _In_ DWORD dwFlags) override;
150 STDMETHODIMP UnregisterProfile(
151 _In_ REFCLSID rclsid,
152 _In_ LANGID langid,
153 _In_ REFGUID guidProfile,
154 _In_ DWORD dwFlags) override;
155 STDMETHODIMP GetActiveProfile(
156 _In_ REFGUID catid,
157 _Out_ TF_INPUTPROCESSORPROFILE *pProfile) override;
158
159protected:
160 LONG m_cRefs;
161 LANGID m_currentLanguage;
162 struct list m_LanguageProfileNotifySink;
163};
164
165////////////////////////////////////////////////////////////////////////////
166
167class CProfilesEnumGuid
168 : public IEnumGUID
169{
170public:
171 CProfilesEnumGuid();
172 virtual ~CProfilesEnumGuid();
173
174 static HRESULT CreateInstance(CProfilesEnumGuid **ppOut);
175
176 // ** IUnknown methods **
177 STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObj) override;
178 STDMETHODIMP_(ULONG) AddRef() override;
179 STDMETHODIMP_(ULONG) Release() override;
180
181 // ** IEnumGUID methods **
182 STDMETHODIMP Next(
183 _In_ ULONG celt,
184 _Out_ GUID *rgelt,
185 _Out_ ULONG *pceltFetched) override;
186 STDMETHODIMP Skip(_In_ ULONG celt) override;
187 STDMETHODIMP Reset() override;
188 STDMETHODIMP Clone(_Out_ IEnumGUID **ppenum) override;
189
190protected:
191 LONG m_cRefs;
192 HKEY m_key;
193 DWORD m_next_index;
194};
195
196////////////////////////////////////////////////////////////////////////////
197
198class CEnumTfLanguageProfiles
199 : public IEnumTfLanguageProfiles
200{
201public:
202 CEnumTfLanguageProfiles(LANGID langid);
203 virtual ~CEnumTfLanguageProfiles();
204
205 static HRESULT CreateInstance(LANGID langid, CEnumTfLanguageProfiles **out);
206
207 // ** IUnknown methods **
208 STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObj) override;
209 STDMETHODIMP_(ULONG) AddRef() override;
210 STDMETHODIMP_(ULONG) Release() override;
211
212 // ** IEnumTfLanguageProfiles methods **
213 STDMETHODIMP Clone(_Out_ IEnumTfLanguageProfiles **ppEnum) override;
214 STDMETHODIMP Next(
215 _In_ ULONG ulCount,
216 _Out_ TF_LANGUAGEPROFILE *pProfile,
217 _Out_ ULONG *pcFetch) override;
218 STDMETHODIMP Reset() override;
219 STDMETHODIMP Skip(_In_ ULONG ulCount) override;
220
221protected:
222 LONG m_cRefs;
223 HKEY m_tipkey;
224 DWORD m_tip_index;
225 WCHAR m_szwCurrentClsid[39];
226 HKEY m_langkey;
227 DWORD m_lang_index;
228 LANGID m_langid;
229 ITfCategoryMgr *m_catmgr;
230
231 INT next_LanguageProfile(CLSID clsid, TF_LANGUAGEPROFILE *tflp);
232};
233
234////////////////////////////////////////////////////////////////////////////
235
236class CEnumTfInputProcessorProfiles
237 : public IEnumTfInputProcessorProfiles
238{
239public:
240 CEnumTfInputProcessorProfiles();
241 virtual ~CEnumTfInputProcessorProfiles();
242
243 // ** IUnknown methods **
244 STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObj) override;
245 STDMETHODIMP_(ULONG) AddRef() override;
246 STDMETHODIMP_(ULONG) Release() override;
247
248 // ** IEnumTfInputProcessorProfiles methods **
249 STDMETHODIMP Clone(_Out_ IEnumTfInputProcessorProfiles **ppEnum) override;
250 STDMETHODIMP Next(
251 _In_ ULONG ulCount,
252 _Out_ TF_INPUTPROCESSORPROFILE *pProfile,
253 _Out_ ULONG *pcFetch) override;
254 STDMETHODIMP Reset() override;
255 STDMETHODIMP Skip(_In_ ULONG ulCount) override;
256
257protected:
258 LONG m_cRefs;
259};
260
261////////////////////////////////////////////////////////////////////////////
262
263static void
264add_userkey(_In_ REFCLSID rclsid, _In_ LANGID langid, _In_ REFGUID guidProfile)
265{
266 HKEY key;
267 WCHAR buf[39], buf2[39], fullkey[168];
268 DWORD disposition = 0;
269 LSTATUS error;
270
271 TRACE("\n");
272
273 StringFromGUID2(rclsid, buf, _countof(buf));
274 StringFromGUID2(guidProfile, buf2, _countof(buf2));
275 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\%s\\0x%08x\\%s",
276 szwSystemTIPKey, buf, L"LanguageProfile", langid, buf2);
277
278 error = RegCreateKeyExW(HKEY_CURRENT_USER, fullkey, 0, NULL, 0,
279 KEY_READ | KEY_WRITE, NULL, &key, &disposition);
280
281 if (error == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
282 {
283 DWORD zero = 0;
284 RegSetValueExW(key, L"Enable", 0, REG_DWORD, (PBYTE)&zero, sizeof(DWORD));
285 }
286
287 if (error == ERROR_SUCCESS)
288 RegCloseKey(key);
289}
290
291////////////////////////////////////////////////////////////////////////////
292
293CInputProcessorProfiles::CInputProcessorProfiles()
294 : m_cRefs(1)
295 , m_currentLanguage(::GetUserDefaultLCID())
296{
297 list_init(&m_LanguageProfileNotifySink);
298}
299
300CInputProcessorProfiles::~CInputProcessorProfiles()
301{
302 TRACE("destroying %p\n", this);
303 free_sinks(&m_LanguageProfileNotifySink);
304}
305
306STDMETHODIMP CInputProcessorProfiles::QueryInterface(REFIID iid, LPVOID *ppvObj)
307{
308 *ppvObj = NULL;
309
310 if (iid == IID_IUnknown || iid == IID_ITfInputProcessorProfiles)
311 *ppvObj = static_cast<ITfInputProcessorProfiles *>(this);
312 else if (iid == IID_ITfInputProcessorProfileMgr)
313 *ppvObj = static_cast<ITfInputProcessorProfileMgr *>(this);
314 else if (iid == IID_ITfSource)
315 *ppvObj = static_cast<ITfSource *>(this);
316
317 if (!*ppvObj)
318 {
319 WARN("unsupported interface: %s\n", debugstr_guid(&iid));
320 return E_NOINTERFACE;
321 }
322
323 AddRef();
324 return S_OK;
325}
326
327STDMETHODIMP_(ULONG) CInputProcessorProfiles::AddRef()
328{
329 return ::InterlockedIncrement(&m_cRefs);
330}
331
332STDMETHODIMP_(ULONG) CInputProcessorProfiles::Release()
333{
334 ULONG ret = ::InterlockedDecrement(&m_cRefs);
335 if (!ret)
336 delete this;
337 return ret;
338}
339
340STDMETHODIMP CInputProcessorProfiles::Register(_In_ REFCLSID rclsid)
341{
342 HKEY tipkey;
343 WCHAR buf[39], fullkey[68];
344
345 TRACE("(%p) %s\n", this, debugstr_guid(&rclsid));
346
347 StringFromGUID2(rclsid, buf, _countof(buf));
348 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s", szwSystemTIPKey, buf);
349
350 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
351 &tipkey, NULL) != ERROR_SUCCESS)
352 {
353 return E_FAIL;
354 }
355
356 RegCloseKey(tipkey);
357 return S_OK;
358}
359
360STDMETHODIMP CInputProcessorProfiles::Unregister(_In_ REFCLSID rclsid)
361{
362 WCHAR buf[39], fullkey[68];
363
364 TRACE("(%p) %s\n", this, debugstr_guid(&rclsid));
365
366 StringFromGUID2(rclsid, buf, _countof(buf));
367 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s", szwSystemTIPKey, buf);
368
369 RegDeleteTreeW(HKEY_LOCAL_MACHINE, fullkey);
370 RegDeleteTreeW(HKEY_CURRENT_USER, fullkey);
371 return S_OK;
372}
373
374STDMETHODIMP CInputProcessorProfiles::AddLanguageProfile(
375 _In_ REFCLSID rclsid,
376 _In_ LANGID langid,
377 _In_ REFGUID guidProfile,
378 _In_ const WCHAR *pchDesc,
379 _In_ ULONG cchDesc,
380 _In_ const WCHAR *pchIconFile,
381 _In_ ULONG cchFile,
382 _In_ ULONG uIconIndex)
383{
384 HKEY tipkey, fmtkey;
385 WCHAR buf[39], fullkey[100];
386 DWORD disposition = 0;
387 LSTATUS error;
388
389 TRACE("(%p) %s %x %s %s %s %i\n", this, debugstr_guid(&rclsid), langid,
390 debugstr_guid(&guidProfile), debugstr_wn(pchDesc, cchDesc),
391 debugstr_wn(pchIconFile, cchFile), uIconIndex);
392
393 StringFromGUID2(rclsid, buf, _countof(buf));
394 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s", szwSystemTIPKey, buf);
395
396 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &tipkey);
397 if (error != ERROR_SUCCESS)
398 return E_FAIL;
399
400 StringFromGUID2(guidProfile, buf, _countof(buf));
401 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\0x%08x\\%s", L"LanguageProfile", langid, buf);
402
403 error = RegCreateKeyExW(tipkey, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
404 NULL, &fmtkey, &disposition);
405 if (error == ERROR_SUCCESS)
406 {
407 DWORD zero = 0x0;
408 RegSetValueExW(fmtkey, L"Description", 0, REG_SZ, (PBYTE)pchDesc, cchDesc * sizeof(WCHAR));
409 RegSetValueExW(fmtkey, L"IconFile", 0, REG_SZ, (PBYTE)pchIconFile, cchFile * sizeof(WCHAR));
410 RegSetValueExW(fmtkey, L"IconIndex", 0, REG_DWORD, (PBYTE)&uIconIndex, sizeof(uIconIndex));
411 if (disposition == REG_CREATED_NEW_KEY)
412 RegSetValueExW(fmtkey, L"Enable", 0, REG_DWORD, (PBYTE)&zero, sizeof(DWORD));
413 RegCloseKey(fmtkey);
414 add_userkey(rclsid, langid, guidProfile);
415 }
416 RegCloseKey(tipkey);
417
418 return (error == ERROR_SUCCESS) ? S_OK : E_FAIL;
419}
420
421STDMETHODIMP CInputProcessorProfiles::RemoveLanguageProfile(
422 _In_ REFCLSID rclsid,
423 _In_ LANGID langid,
424 _In_ REFGUID guidProfile)
425{
426 FIXME("STUB:(%p)\n", this);
427 return E_NOTIMPL;
428}
429
430STDMETHODIMP CInputProcessorProfiles::EnumInputProcessorInfo(_Out_ IEnumGUID **ppEnum)
431{
432 TRACE("(%p) %p\n", this, ppEnum);
433
434 return CProfilesEnumGuid::CreateInstance((CProfilesEnumGuid **)ppEnum);
435}
436
437STDMETHODIMP CInputProcessorProfiles::GetDefaultLanguageProfile(
438 _In_ LANGID langid,
439 _In_ REFGUID catid,
440 _Out_ CLSID *pclsid,
441 _Out_ GUID *pguidProfile)
442{
443 WCHAR fullkey[168], buf[39];
444 HKEY hKey;
445 DWORD count;
446 LSTATUS error;
447
448 TRACE("%p) %x %s %p %p\n", this, langid, debugstr_guid(&catid), pclsid, pguidProfile);
449
450 if (cicIsNullPtr(&catid) || !pclsid || !pguidProfile)
451 return E_INVALIDARG;
452
453 StringFromGUID2(catid, buf, _countof(buf));
454 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\0x%08x\\%s", szwSystemCTFKey,
455 L"Assemblies", langid, buf);
456
457 error = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &hKey);
458 if (error != ERROR_SUCCESS)
459 return S_FALSE;
460
461 count = sizeof(buf);
462 error = RegQueryValueExW(hKey, L"Default", 0, NULL, (PBYTE)buf, &count);
463 if (error != ERROR_SUCCESS)
464 {
465 RegCloseKey(hKey);
466 return S_FALSE;
467 }
468 CLSIDFromString(buf, pclsid);
469
470 error = RegQueryValueExW(hKey, L"Profile", 0, NULL, (PBYTE)buf, &count);
471 if (error == ERROR_SUCCESS)
472 CLSIDFromString(buf, pguidProfile);
473
474 RegCloseKey(hKey);
475
476 return S_OK;
477}
478
479STDMETHODIMP CInputProcessorProfiles::SetDefaultLanguageProfile(
480 _In_ LANGID langid,
481 _In_ REFCLSID rclsid,
482 _In_ REFGUID guidProfiles)
483{
484 WCHAR fullkey[168], buf[39];
485 HKEY hKey;
486 GUID catid;
487 HRESULT hr;
488 ITfCategoryMgr *catmgr;
489 LSTATUS error;
490 static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
491 &GUID_TFCAT_TIP_SPEECH,
492 &GUID_TFCAT_TIP_HANDWRITING };
493
494 TRACE("(%p) %x %s %s\n", this, langid, debugstr_guid(&rclsid), debugstr_guid(&guidProfiles));
495
496 if (cicIsNullPtr(&rclsid) || cicIsNullPtr(&guidProfiles))
497 return E_INVALIDARG;
498
499 hr = CategoryMgr_Constructor(NULL, (IUnknown**)&catmgr);
500 if (FAILED(hr))
501 return hr;
502
503 if (catmgr->FindClosestCategory(rclsid, &catid, tipcats, _countof(tipcats)) != S_OK)
504 hr = catmgr->FindClosestCategory(rclsid, &catid, NULL, 0);
505 catmgr->Release();
506 if (FAILED(hr))
507 return E_FAIL;
508
509 StringFromGUID2(catid, buf, _countof(buf));
510 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\0x%08x\\%s", szwSystemCTFKey, L"Assemblies", langid, buf);
511
512 error = RegCreateKeyExW(HKEY_CURRENT_USER, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
513 NULL, &hKey, NULL);
514 if (error != ERROR_SUCCESS)
515 return E_FAIL;
516
517 StringFromGUID2(rclsid, buf, _countof(buf));
518 RegSetValueExW(hKey, L"Default", 0, REG_SZ, (PBYTE)buf, sizeof(buf));
519 StringFromGUID2(guidProfiles, buf, _countof(buf));
520 RegSetValueExW(hKey, L"Profile", 0, REG_SZ, (PBYTE)buf, sizeof(buf));
521 RegCloseKey(hKey);
522
523 return S_OK;
524}
525
526STDMETHODIMP CInputProcessorProfiles::ActivateLanguageProfile(
527 _In_ REFCLSID rclsid,
528 _In_ LANGID langid,
529 _In_ REFGUID guidProfiles)
530{
531 HRESULT hr;
532 BOOL enabled;
533 TF_LANGUAGEPROFILE LanguageProfile;
534
535 TRACE("(%p) %s %x %s\n", this, debugstr_guid(&rclsid), langid, debugstr_guid(&guidProfiles));
536
537 if (langid != m_currentLanguage)
538 return E_INVALIDARG;
539
540 if (get_active_textservice(rclsid, NULL))
541 {
542 TRACE("Already Active\n");
543 return E_FAIL;
544 }
545
546 hr = IsEnabledLanguageProfile(rclsid, langid, guidProfiles, &enabled);
547 if (FAILED(hr) || !enabled)
548 {
549 TRACE("Not Enabled\n");
550 return E_FAIL;
551 }
552
553 LanguageProfile.clsid = rclsid;
554 LanguageProfile.langid = langid;
555 LanguageProfile.guidProfile = guidProfiles;
556 LanguageProfile.fActive = TRUE;
557 return add_active_textservice(&LanguageProfile);
558}
559
560STDMETHODIMP CInputProcessorProfiles::GetActiveLanguageProfile(
561 _In_ REFCLSID rclsid,
562 _Out_ LANGID *plangid,
563 _Out_ GUID *pguidProfile)
564{
565 TF_LANGUAGEPROFILE profile;
566
567 TRACE("(%p) %s %p %p\n", this, debugstr_guid(&rclsid), plangid, pguidProfile);
568
569 if (cicIsNullPtr(&rclsid) || !plangid || !pguidProfile)
570 return E_INVALIDARG;
571
572 if (get_active_textservice(rclsid, &profile))
573 {
574 *plangid = profile.langid;
575 *pguidProfile = profile.guidProfile;
576 return S_OK;
577 }
578 else
579 {
580 *pguidProfile = GUID_NULL;
581 return S_FALSE;
582 }
583}
584
585STDMETHODIMP CInputProcessorProfiles::GetLanguageProfileDescription(
586 _In_ REFCLSID rclsid,
587 _In_ LANGID langid,
588 _In_ REFGUID guidProfile,
589 _Out_ BSTR *pbstrProfile)
590{
591 FIXME("STUB:(%p)\n", this);
592 return E_NOTIMPL;
593}
594
595STDMETHODIMP CInputProcessorProfiles::GetCurrentLanguage(_Out_ LANGID *plangid)
596{
597 TRACE("(%p) 0x%x\n", this, m_currentLanguage);
598
599 if (!plangid)
600 return E_INVALIDARG;
601
602 *plangid = m_currentLanguage;
603 return S_OK;
604}
605
606STDMETHODIMP CInputProcessorProfiles::ChangeCurrentLanguage(_In_ LANGID langid)
607{
608 ITfLanguageProfileNotifySink *sink;
609 struct list *cursor;
610 BOOL accept;
611
612 FIXME("STUB:(%p)\n", this);
613
614 SINK_FOR_EACH(cursor, &m_LanguageProfileNotifySink, ITfLanguageProfileNotifySink, sink)
615 {
616 accept = TRUE;
617 sink->OnLanguageChange(langid, &accept);
618 if (!accept)
619 return E_FAIL;
620 }
621
622 /* TODO: On successful language change call OnLanguageChanged sink */
623 return E_NOTIMPL;
624}
625
626STDMETHODIMP CInputProcessorProfiles::GetLanguageList(
627 _Out_ LANGID **ppLangId,
628 _Out_ ULONG *pulCount)
629{
630 FIXME("Semi-STUB:(%p)\n", this);
631 *ppLangId = (LANGID *)CoTaskMemAlloc(sizeof(LANGID));
632 **ppLangId = m_currentLanguage;
633 *pulCount = 1;
634 return S_OK;
635}
636
637STDMETHODIMP CInputProcessorProfiles::EnumLanguageProfiles(
638 _In_ LANGID langid,
639 _Out_ IEnumTfLanguageProfiles **ppEnum)
640{
641 TRACE("(%p) %x %p\n", this, langid, ppEnum);
642
643 if (!ppEnum)
644 return E_INVALIDARG;
645
646 CEnumTfLanguageProfiles *profenum;
647 HRESULT hr = CEnumTfLanguageProfiles::CreateInstance(langid, &profenum);
648 *ppEnum = static_cast<IEnumTfLanguageProfiles *>(profenum);
649 return hr;
650}
651
652STDMETHODIMP CInputProcessorProfiles::EnableLanguageProfile(
653 _In_ REFCLSID rclsid,
654 _In_ LANGID langid,
655 _In_ REFGUID guidProfile,
656 _In_ BOOL fEnable)
657{
658 HKEY key;
659 WCHAR buf[39], buf2[39], fullkey[168];
660 LSTATUS error;
661
662 TRACE("(%p) %s %x %s %i\n", this, debugstr_guid(&rclsid), langid, debugstr_guid(&guidProfile), fEnable);
663
664 StringFromGUID2(rclsid, buf, _countof(buf));
665 StringFromGUID2(guidProfile, buf2, _countof(buf2));
666 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\%s\\0x%08x\\%s", szwSystemTIPKey, buf,
667 L"LanguageProfile", langid, buf2);
668
669 error = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
670 if (error != ERROR_SUCCESS)
671 return E_FAIL;
672
673 RegSetValueExW(key, L"Enable", 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(fEnable));
674 RegCloseKey(key);
675 return S_OK;
676}
677
678STDMETHODIMP CInputProcessorProfiles::IsEnabledLanguageProfile(
679 _In_ REFCLSID rclsid,
680 _In_ LANGID langid,
681 _In_ REFGUID guidProfile,
682 _Out_ BOOL *pfEnable)
683{
684 HKEY key;
685 WCHAR buf[39], buf2[39], fullkey[168];
686 LSTATUS error;
687
688 TRACE("(%p) %s, %i, %s, %p\n", this, debugstr_guid(&rclsid), langid, debugstr_guid(&guidProfile), pfEnable);
689
690 if (!pfEnable)
691 return E_INVALIDARG;
692
693 StringFromGUID2(rclsid, buf, _countof(buf));
694 StringFromGUID2(guidProfile, buf2, _countof(buf2));
695 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\%s\\0x%08x\\%s", szwSystemTIPKey,
696 buf, L"LanguageProfile", langid, buf2);
697
698 error = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
699 if (error == ERROR_SUCCESS)
700 {
701 DWORD count = sizeof(DWORD);
702 error = RegQueryValueExW(key, L"Enable", 0, NULL, (LPBYTE)pfEnable, &count);
703 RegCloseKey(key);
704 }
705
706 if (error != ERROR_SUCCESS) /* Try Default */
707 {
708 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
709 if (error == ERROR_SUCCESS)
710 {
711 DWORD count = sizeof(DWORD);
712 error = RegQueryValueExW(key, L"Enable", 0, NULL, (LPBYTE)pfEnable, &count);
713 RegCloseKey(key);
714 }
715 }
716
717 return (error == ERROR_SUCCESS) ? S_OK : E_FAIL;
718}
719
720STDMETHODIMP CInputProcessorProfiles::EnableLanguageProfileByDefault(
721 _In_ REFCLSID rclsid,
722 _In_ LANGID langid,
723 _In_ REFGUID guidProfile,
724 _In_ BOOL fEnable)
725{
726 HKEY key;
727 WCHAR buf[39], buf2[39], fullkey[168];
728 LSTATUS error;
729
730 TRACE("(%p) %s %x %s %i\n", this, debugstr_guid(&rclsid), langid, debugstr_guid(&guidProfile), fEnable);
731
732 StringFromGUID2(rclsid, buf, _countof(buf));
733 StringFromGUID2(guidProfile, buf2, _countof(buf2));
734 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\%s\\0x%08x\\%s", szwSystemTIPKey,
735 buf, L"LanguageProfile", langid, buf2);
736
737 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
738 if (error != ERROR_SUCCESS)
739 return E_FAIL;
740
741 RegSetValueExW(key, L"Enable", 0, REG_DWORD, (PBYTE)&fEnable, sizeof(fEnable));
742 RegCloseKey(key);
743 return S_OK;
744}
745
746STDMETHODIMP CInputProcessorProfiles::SubstituteKeyboardLayout(
747 _In_ REFCLSID rclsid,
748 _In_ LANGID langid,
749 _In_ REFGUID guidProfile,
750 _In_ HKL hKL)
751{
752 FIXME("STUB:(%p)\n", this);
753 return E_NOTIMPL;
754}
755
756STDMETHODIMP CInputProcessorProfiles::ActivateProfile(
757 _In_ DWORD dwProfileType,
758 _In_ LANGID langid,
759 _In_ REFCLSID clsid,
760 _In_ REFGUID guidProfile,
761 _In_ HKL hkl,
762 _In_ DWORD dwFlags)
763{
764 FIXME("(%p)->(%d %x %s %s %p %x)\n", this, dwProfileType, langid, debugstr_guid(&clsid),
765 debugstr_guid(&guidProfile), hkl, dwFlags);
766 return E_NOTIMPL;
767}
768
769STDMETHODIMP CInputProcessorProfiles::DeactivateProfile(
770 _In_ DWORD dwProfileType,
771 _In_ LANGID langid,
772 _In_ REFCLSID clsid,
773 _In_ REFGUID guidProfile,
774 _In_ HKL hkl,
775 _In_ DWORD dwFlags)
776{
777 FIXME("(%p)->(%d %x %s %s %p %x)\n", this, dwProfileType, langid, debugstr_guid(&clsid),
778 debugstr_guid(&guidProfile), hkl, dwFlags);
779 return E_NOTIMPL;
780}
781
782STDMETHODIMP CInputProcessorProfiles::GetProfile(
783 _In_ DWORD dwProfileType,
784 _In_ LANGID langid,
785 _In_ REFCLSID clsid,
786 _In_ REFGUID guidProfile,
787 _In_ HKL hkl,
788 _Out_ TF_INPUTPROCESSORPROFILE *pProfile)
789{
790 FIXME("(%p)->(%d %x %s %s %p %p)\n", this, dwProfileType, langid, debugstr_guid(&clsid),
791 debugstr_guid(&guidProfile), hkl, pProfile);
792 return E_NOTIMPL;
793}
794
795STDMETHODIMP CInputProcessorProfiles::EnumProfiles(
796 _In_ LANGID langid,
797 _Out_ IEnumTfInputProcessorProfiles **ppEnum)
798{
799 TRACE("(%p)->(%x %p)\n", this, langid, ppEnum);
800
801 CEnumTfInputProcessorProfiles *enum_profiles = new(cicNoThrow) CEnumTfInputProcessorProfiles();
802 if (!enum_profiles)
803 return E_OUTOFMEMORY;
804
805 *ppEnum = static_cast<IEnumTfInputProcessorProfiles *>(enum_profiles);
806 return S_OK;
807}
808
809STDMETHODIMP CInputProcessorProfiles::ReleaseInputProcessor(
810 _In_ REFCLSID rclsid,
811 _In_ DWORD dwFlags)
812{
813 FIXME("(%p)->(%s %x)\n", this, debugstr_guid(&rclsid), dwFlags);
814 return E_NOTIMPL;
815}
816
817STDMETHODIMP CInputProcessorProfiles::RegisterProfile(
818 _In_ REFCLSID rclsid,
819 _In_ LANGID langid,
820 _In_ REFGUID guidProfile,
821 _In_ const WCHAR *pchDesc,
822 _In_ ULONG cchDesc,
823 _In_ const WCHAR *pchIconFile,
824 _In_ ULONG cchFile,
825 _In_ ULONG uIconIndex,
826 _In_ HKL hklsubstitute,
827 _In_ DWORD dwPreferredLayout,
828 _In_ BOOL bEnabledByDefault,
829 _In_ DWORD dwFlags)
830{
831 FIXME("(%p)->(%s %x %s %s %d %s %u %u %p %x %x %x)\n", this, debugstr_guid(&rclsid), langid,
832 debugstr_guid(&guidProfile), debugstr_w(pchDesc), cchDesc, debugstr_w(pchIconFile),
833 cchFile, uIconIndex, hklsubstitute, dwPreferredLayout, bEnabledByDefault, dwFlags);
834 return E_NOTIMPL;
835}
836
837STDMETHODIMP CInputProcessorProfiles::UnregisterProfile(
838 _In_ REFCLSID rclsid,
839 _In_ LANGID langid,
840 _In_ REFGUID guidProfile,
841 _In_ DWORD dwFlags)
842{
843 FIXME("(%p)->(%s %x %s %x)\n", this, debugstr_guid(&rclsid), langid,
844 debugstr_guid(&guidProfile), dwFlags);
845 return E_NOTIMPL;
846}
847
848STDMETHODIMP CInputProcessorProfiles::GetActiveProfile(
849 _In_ REFGUID catid,
850 _Out_ TF_INPUTPROCESSORPROFILE *pProfile)
851{
852 FIXME("(%p)->(%s %p)\n", this, debugstr_guid(&catid), pProfile);
853 return E_NOTIMPL;
854}
855
856STDMETHODIMP CInputProcessorProfiles::AdviseSink(
857 _In_ REFIID riid,
858 _In_ IUnknown *punk,
859 _Out_ DWORD *pdwCookie)
860{
861 TRACE("(%p) %s %p %p\n", this, debugstr_guid(&riid), punk, pdwCookie);
862
863 if (cicIsNullPtr(&riid) || !punk || !pdwCookie)
864 return E_INVALIDARG;
865
866 if (riid == IID_ITfLanguageProfileNotifySink)
867 return advise_sink(&m_LanguageProfileNotifySink, IID_ITfLanguageProfileNotifySink,
868 COOKIE_MAGIC_IPPSINK, punk, pdwCookie);
869
870 FIXME("(%p) Unhandled Sink: %s\n", this, debugstr_guid(&riid));
871 return E_NOTIMPL;
872}
873
874STDMETHODIMP CInputProcessorProfiles::UnadviseSink(_In_ DWORD dwCookie)
875{
876 TRACE("(%p) %x\n", this, dwCookie);
877
878 if (get_Cookie_magic(dwCookie) != COOKIE_MAGIC_IPPSINK)
879 return E_INVALIDARG;
880
881 return unadvise_sink(dwCookie);
882}
883
884HRESULT CInputProcessorProfiles::CreateInstance(IUnknown *pUnkOuter, CInputProcessorProfiles **ppOut)
885{
886 if (pUnkOuter)
887 return CLASS_E_NOAGGREGATION;
888
889 CInputProcessorProfiles *This = new(cicNoThrow) CInputProcessorProfiles();
890 if (!This)
891 return E_OUTOFMEMORY;
892
893 *ppOut = This;
894 TRACE("returning %p\n", *ppOut);
895 return S_OK;
896}
897
898////////////////////////////////////////////////////////////////////////////
899
900CProfilesEnumGuid::CProfilesEnumGuid()
901 : m_cRefs(1)
902 , m_key(NULL)
903 , m_next_index(0)
904{
905}
906
907CProfilesEnumGuid::~CProfilesEnumGuid()
908{
909 TRACE("destroying %p\n", this);
910 RegCloseKey(m_key);
911}
912
913STDMETHODIMP CProfilesEnumGuid::QueryInterface(REFIID iid, LPVOID *ppvObj)
914{
915 *ppvObj = NULL;
916
917 if (iid == IID_IUnknown || iid == IID_IEnumGUID)
918 *ppvObj = static_cast<IEnumGUID *>(this);
919
920 if (*ppvObj)
921 {
922 AddRef();
923 return S_OK;
924 }
925
926 WARN("unsupported interface: %s\n", debugstr_guid(&iid));
927 return E_NOINTERFACE;
928}
929
930STDMETHODIMP_(ULONG) CProfilesEnumGuid::AddRef()
931{
932 return ::InterlockedIncrement(&m_cRefs);
933}
934
935STDMETHODIMP_(ULONG) CProfilesEnumGuid::Release()
936{
937 ULONG ret = ::InterlockedDecrement(&m_cRefs);
938 if (!ret)
939 delete this;
940 return ret;
941}
942
943STDMETHODIMP CProfilesEnumGuid::Next(
944 _In_ ULONG celt,
945 _Out_ GUID *rgelt,
946 _Out_ ULONG *pceltFetched)
947{
948 ULONG fetched = 0;
949
950 TRACE("(%p)\n", this);
951
952 if (!rgelt)
953 return E_POINTER;
954
955 if (m_key)
956 {
957 while (fetched < celt)
958 {
959 LSTATUS error;
960 HRESULT hr;
961 WCHAR catid[39];
962 DWORD cName = _countof(catid);
963
964 error = RegEnumKeyExW(m_key, m_next_index, catid, &cName, NULL, NULL, NULL, NULL);
965 if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA)
966 break;
967
968 ++m_next_index;
969
970 hr = CLSIDFromString(catid, rgelt);
971 if (FAILED(hr))
972 continue;
973
974 ++fetched;
975 ++rgelt;
976 }
977 }
978
979 if (pceltFetched)
980 *pceltFetched = fetched;
981 return fetched == celt ? S_OK : S_FALSE;
982}
983
984STDMETHODIMP CProfilesEnumGuid::Skip(_In_ ULONG celt)
985{
986 TRACE("(%p)\n", this);
987 m_next_index += celt;
988 return S_OK;
989}
990
991STDMETHODIMP CProfilesEnumGuid::Reset()
992{
993 TRACE("(%p)\n", this);
994 m_next_index = 0;
995 return S_OK;
996}
997
998STDMETHODIMP CProfilesEnumGuid::Clone(_Out_ IEnumGUID **ppenum)
999{
1000 TRACE("(%p)\n", this);
1001
1002 if (!ppenum)
1003 return E_POINTER;
1004
1005 *ppenum = NULL;
1006
1007 CProfilesEnumGuid *pEnum;
1008 HRESULT hr = CProfilesEnumGuid::CreateInstance(&pEnum);
1009 if (SUCCEEDED(hr))
1010 {
1011 pEnum->m_next_index = m_next_index;
1012 *ppenum = static_cast<IEnumGUID *>(pEnum);
1013 }
1014
1015 return hr;
1016}
1017
1018HRESULT CProfilesEnumGuid::CreateInstance(CProfilesEnumGuid **ppOut)
1019{
1020 CProfilesEnumGuid *This = new(cicNoThrow) CProfilesEnumGuid();
1021 if (!This)
1022 return E_OUTOFMEMORY;
1023
1024 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
1025 KEY_READ | KEY_WRITE, NULL, &This->m_key, NULL) != ERROR_SUCCESS)
1026 {
1027 delete This;
1028 return E_FAIL;
1029 }
1030
1031 *ppOut = This;
1032 TRACE("returning %p\n", *ppOut);
1033 return S_OK;
1034}
1035
1036////////////////////////////////////////////////////////////////////////////
1037
1038CEnumTfLanguageProfiles::CEnumTfLanguageProfiles(LANGID langid)
1039 : m_cRefs(1)
1040 , m_langid(langid)
1041{
1042}
1043
1044CEnumTfLanguageProfiles::~CEnumTfLanguageProfiles()
1045{
1046 TRACE("destroying %p\n", this);
1047 RegCloseKey(m_tipkey);
1048 if (m_langkey)
1049 RegCloseKey(m_langkey);
1050 m_catmgr->Release();
1051}
1052
1053HRESULT CEnumTfLanguageProfiles::CreateInstance(LANGID langid, CEnumTfLanguageProfiles **out)
1054{
1055 HRESULT hr;
1056 CEnumTfLanguageProfiles *This = new(cicNoThrow) CEnumTfLanguageProfiles(langid);
1057 if (!This)
1058 return E_OUTOFMEMORY;
1059
1060 hr = CategoryMgr_Constructor(NULL, (IUnknown**)&This->m_catmgr);
1061 if (FAILED(hr))
1062 {
1063 delete This;
1064 return hr;
1065 }
1066
1067 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
1068 KEY_READ | KEY_WRITE, NULL, &This->m_tipkey, NULL) != ERROR_SUCCESS)
1069 {
1070 delete This;
1071 return E_FAIL;
1072 }
1073
1074 *out = This;
1075 TRACE("returning %p\n", *out);
1076 return S_OK;
1077}
1078
1079STDMETHODIMP CEnumTfLanguageProfiles::QueryInterface(REFIID iid, LPVOID *ppvObj)
1080{
1081 *ppvObj = NULL;
1082
1083 if (iid == IID_IUnknown || iid == IID_IEnumTfLanguageProfiles)
1084 *ppvObj = static_cast<IEnumTfLanguageProfiles *>(this);
1085
1086 if (*ppvObj)
1087 {
1088 AddRef();
1089 return S_OK;
1090 }
1091
1092 WARN("unsupported interface: %s\n", debugstr_guid(&iid));
1093 return E_NOINTERFACE;
1094}
1095
1096STDMETHODIMP_(ULONG) CEnumTfLanguageProfiles::AddRef()
1097{
1098 return ::InterlockedIncrement(&m_cRefs);
1099}
1100
1101STDMETHODIMP_(ULONG) CEnumTfLanguageProfiles::Release()
1102{
1103 ULONG ret = ::InterlockedDecrement(&m_cRefs);
1104 if (!ret)
1105 delete this;
1106 return ret;
1107}
1108
1109INT CEnumTfLanguageProfiles::next_LanguageProfile(CLSID clsid, TF_LANGUAGEPROFILE *tflp)
1110{
1111 WCHAR fullkey[168], profileid[39];
1112 LSTATUS error;
1113 DWORD cName = _countof(profileid);
1114 GUID profile;
1115
1116 if (!m_langkey)
1117 {
1118 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\0x%08x", m_szwCurrentClsid,
1119 L"LanguageProfile", m_langid);
1120 error = RegOpenKeyExW(m_tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &m_langkey);
1121 if (error != ERROR_SUCCESS)
1122 {
1123 m_langkey = NULL;
1124 return -1;
1125 }
1126 m_lang_index = 0;
1127 }
1128
1129 error = RegEnumKeyExW(m_langkey, m_lang_index, profileid, &cName, NULL, NULL, NULL, NULL);
1130 if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA)
1131 {
1132 RegCloseKey(m_langkey);
1133 m_langkey = NULL;
1134 return -1;
1135 }
1136 ++m_lang_index;
1137
1138 if (tflp)
1139 {
1140 static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
1141 &GUID_TFCAT_TIP_SPEECH,
1142 &GUID_TFCAT_TIP_HANDWRITING };
1143 HRESULT hr = CLSIDFromString(profileid, &profile);
1144 if (FAILED(hr))
1145 return 0;
1146
1147 tflp->clsid = clsid;
1148 tflp->langid = m_langid;
1149 tflp->fActive = get_active_textservice(clsid, NULL);
1150 tflp->guidProfile = profile;
1151 if (m_catmgr->FindClosestCategory(clsid, &tflp->catid, tipcats, 3) != S_OK)
1152 m_catmgr->FindClosestCategory(clsid, &tflp->catid, NULL, 0);
1153 }
1154
1155 return 1;
1156}
1157
1158STDMETHODIMP CEnumTfLanguageProfiles::Next(
1159 _In_ ULONG ulCount,
1160 _Out_ TF_LANGUAGEPROFILE *pProfile,
1161 _Out_ ULONG *pcFetch)
1162{
1163 ULONG fetched = 0;
1164
1165 TRACE("(%p)\n", this);
1166
1167 if (!pProfile)
1168 return E_POINTER;
1169
1170 if (m_tipkey)
1171 {
1172 while (fetched < ulCount)
1173 {
1174 LSTATUS error;
1175 HRESULT hr;
1176 DWORD cName = _countof(m_szwCurrentClsid);
1177 CLSID clsid;
1178
1179 error = RegEnumKeyExW(m_tipkey, m_tip_index, m_szwCurrentClsid, &cName, NULL, NULL,
1180 NULL, NULL);
1181 if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA)
1182 break;
1183
1184 ++m_tip_index;
1185
1186 hr = CLSIDFromString(m_szwCurrentClsid, &clsid);
1187 if (FAILED(hr))
1188 continue;
1189
1190 while (fetched < ulCount)
1191 {
1192 INT res = next_LanguageProfile(clsid, pProfile);
1193 if (res == 1)
1194 {
1195 ++fetched;
1196 ++pProfile;
1197 }
1198 else if (res == -1)
1199 {
1200 break;
1201 }
1202 }
1203 }
1204 }
1205
1206 if (pcFetch)
1207 *pcFetch = fetched;
1208 return (fetched == ulCount) ? S_OK : S_FALSE;
1209}
1210
1211STDMETHODIMP CEnumTfLanguageProfiles::Skip(_In_ ULONG celt)
1212{
1213 FIXME("STUB (%p)\n", this);
1214 return E_NOTIMPL;
1215}
1216
1217STDMETHODIMP CEnumTfLanguageProfiles::Reset()
1218{
1219 TRACE("(%p)\n", this);
1220 m_tip_index = 0;
1221 if (m_langkey)
1222 RegCloseKey(m_langkey);
1223 m_langkey = NULL;
1224 m_lang_index = 0;
1225 return S_OK;
1226}
1227
1228STDMETHODIMP CEnumTfLanguageProfiles::Clone(_Out_ IEnumTfLanguageProfiles **ppEnum)
1229{
1230 TRACE("(%p)\n", this);
1231
1232 if (!ppEnum)
1233 return E_POINTER;
1234
1235 *ppEnum = NULL;
1236
1237 CEnumTfLanguageProfiles *new_This;
1238 HRESULT hr = CEnumTfLanguageProfiles::CreateInstance(m_langid, &new_This);
1239 if (FAILED(hr))
1240 return hr;
1241
1242 new_This->m_tip_index = m_tip_index;
1243 lstrcpynW(new_This->m_szwCurrentClsid, m_szwCurrentClsid, _countof(new_This->m_szwCurrentClsid));
1244
1245 if (m_langkey)
1246 {
1247 WCHAR fullkey[168];
1248 StringCchPrintfW(fullkey, _countof(fullkey), L"%s\\%s\\0x%08x", m_szwCurrentClsid, L"LanguageProfile", m_langid);
1249 RegOpenKeyExW(new_This->m_tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &new_This->m_langkey);
1250 new_This->m_lang_index = m_lang_index;
1251 }
1252
1253 *ppEnum = static_cast<IEnumTfLanguageProfiles *>(new_This);
1254 return hr;
1255}
1256
1257////////////////////////////////////////////////////////////////////////////
1258
1259CEnumTfInputProcessorProfiles::CEnumTfInputProcessorProfiles()
1260 : m_cRefs(1)
1261{
1262}
1263
1264CEnumTfInputProcessorProfiles::~CEnumTfInputProcessorProfiles()
1265{
1266}
1267
1268STDMETHODIMP CEnumTfInputProcessorProfiles::QueryInterface(REFIID iid, LPVOID *ppvObj)
1269{
1270 if (!ppvObj)
1271 return E_POINTER;
1272
1273 *ppvObj = NULL;
1274 if (iid == IID_IUnknown || iid == IID_IEnumTfInputProcessorProfiles)
1275 *ppvObj = static_cast<IEnumTfInputProcessorProfiles *>(this);
1276
1277 if (*ppvObj)
1278 {
1279 AddRef();
1280 return S_OK;
1281 }
1282
1283 WARN("unsupported interface: %s\n", debugstr_guid(&iid));
1284 return E_NOINTERFACE;
1285}
1286
1287STDMETHODIMP_(ULONG) CEnumTfInputProcessorProfiles::AddRef()
1288{
1289 return ::InterlockedIncrement(&m_cRefs);
1290}
1291
1292STDMETHODIMP_(ULONG) CEnumTfInputProcessorProfiles::Release()
1293{
1294 ULONG ret = ::InterlockedDecrement(&m_cRefs);
1295 if (!ret)
1296 delete this;
1297 return ret;
1298}
1299
1300STDMETHODIMP CEnumTfInputProcessorProfiles::Clone(_Out_ IEnumTfInputProcessorProfiles **ppEnum)
1301{
1302 FIXME("(%p)->(%p)\n", this, ppEnum);
1303 return E_NOTIMPL;
1304}
1305
1306STDMETHODIMP CEnumTfInputProcessorProfiles::Next(
1307 _In_ ULONG ulCount,
1308 _Out_ TF_INPUTPROCESSORPROFILE *pProfile,
1309 _Out_ ULONG *pcFetch)
1310{
1311 FIXME("(%p)->(%u %p %p)\n", this, ulCount, pProfile, pcFetch);
1312 if (pcFetch)
1313 *pcFetch = 0;
1314 return S_FALSE;
1315}
1316
1317STDMETHODIMP CEnumTfInputProcessorProfiles::Reset()
1318{
1319 FIXME("(%p)\n", this);
1320 return E_NOTIMPL;
1321}
1322
1323STDMETHODIMP CEnumTfInputProcessorProfiles::Skip(_In_ ULONG ulCount)
1324{
1325 FIXME("(%p)->(%u)\n", this, ulCount);
1326 return E_NOTIMPL;
1327}
1328
1329////////////////////////////////////////////////////////////////////////////
1330
1331EXTERN_C
1332HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
1333{
1334 return CInputProcessorProfiles::CreateInstance(pUnkOuter, (CInputProcessorProfiles **)ppOut);
1335}