xref: /reactos/dll/win32/msctf/utils.cpp (revision 69a925ca)
1 /*
2  * PROJECT:     ReactOS msctf.dll
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Text Framework Services
5  * COPYRIGHT:   Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include <stdlib.h>
9 
10 #define WIN32_LEAN_AND_MEAN
11 #define WIN32_NO_STATUS
12 #define COBJMACROS
13 #define INITGUID
14 #define _EXTYPES_H
15 
16 #include <windows.h>
17 #include <imm.h>
18 #include <ddk/immdev.h>
19 #include <cguid.h>
20 #include <tchar.h>
21 #include <msctf.h>
22 #include <ctffunc.h>
23 #include <shlwapi.h>
24 #include <strsafe.h>
25 
26 #include <cicero/cicreg.h>
27 
28 #include <wine/debug.h>
29 
30 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
31 
32 DWORD g_dwOSInfo = 0; // See cicGetOSInfo
33 
34 BOOL StringFromGUID2A(REFGUID rguid, LPSTR pszGUID, INT cchGUID)
35 {
36     pszGUID[0] = ANSI_NULL;
37 
38     WCHAR szWide[40];
39     szWide[0] = UNICODE_NULL;
40     BOOL ret = StringFromGUID2(rguid, szWide, _countof(szWide));
41     ::WideCharToMultiByte(CP_ACP, 0, szWide, -1, pszGUID, cchGUID, NULL, NULL);
42     return ret;
43 }
44 
45 #ifdef UNICODE
46     #define StringFromGUID2T StringFromGUID2
47     #define debugstr_t debugstr_w
48 #else
49     #define StringFromGUID2T StringFromGUID2A
50     #define debugstr_t debugstr_a
51 #endif
52 
53 BOOL FullPathExec(LPCTSTR pszExeFile, LPCTSTR pszCmdLine, UINT nCmdShow, BOOL bSysWinDir)
54 {
55     STARTUPINFO si;
56     PROCESS_INFORMATION pi;
57     CicSystemModulePath ModPath;
58     TCHAR szCommandLine[2 * MAX_PATH];
59 
60     ModPath.Init(pszExeFile, bSysWinDir);
61     if (!ModPath.m_cchPath)
62     {
63         ERR("%s\n", debugstr_t(pszExeFile));
64         return FALSE;
65     }
66 
67     StringCchCopy(szCommandLine, _countof(szCommandLine), pszCmdLine);
68 
69     ZeroMemory(&si, sizeof(si));
70     si.cb = sizeof(si);
71     si.wShowWindow = nCmdShow;
72     si.dwFlags = STARTF_USESHOWWINDOW;
73     if (!CreateProcess(ModPath.m_szPath, szCommandLine, NULL, NULL, FALSE,
74                        NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
75     {
76         ERR("%s, %s\n", debugstr_t(ModPath.m_szPath), debugstr_t(szCommandLine));
77         return FALSE;
78     }
79 
80     CloseHandle(pi.hProcess);
81     CloseHandle(pi.hThread);
82     return TRUE;
83 }
84 
85 static inline BOOL
86 RunCPLSetting(LPCTSTR pszCmdLine)
87 {
88     if (!pszCmdLine)
89         return FALSE;
90 
91     return FullPathExec(TEXT("rundll32.exe"), pszCmdLine, SW_SHOWMINNOACTIVE, FALSE);
92 }
93 
94 /***********************************************************************
95  *      TF_RegisterLangBarAddIn (MSCTF.@)
96  *
97  * @implemented
98  */
99 EXTERN_C HRESULT WINAPI
100 TF_RegisterLangBarAddIn(
101     _In_ REFGUID rguid,
102     _In_ LPCWSTR pszFilePath,
103     _In_ DWORD dwFlags)
104 {
105     TRACE("(%s, %s, 0x%lX)\n", debugstr_guid(&rguid), debugstr_w(pszFilePath), dwFlags);
106 
107     if (!pszFilePath || IsEqualGUID(rguid, GUID_NULL))
108     {
109         ERR("E_INVALIDARG\n");
110         return E_INVALIDARG;
111     }
112 
113     TCHAR szBuff[MAX_PATH], szGUID[40];
114     StringCchCopy(szBuff, _countof(szBuff), TEXT("SOFTWARE\\Microsoft\\CTF\\LangBarAddIn\\"));
115     StringFromGUID2T(rguid, szGUID, _countof(szGUID));
116     StringCchCat(szBuff, _countof(szBuff), szGUID);
117 
118     CicRegKey regKey;
119     HKEY hBaseKey = ((dwFlags & 1) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
120     LSTATUS error = regKey.Create(hBaseKey, szBuff);
121     if (error == ERROR_SUCCESS)
122     {
123         error = regKey.SetSzW(L"FilePath", pszFilePath);
124         if (error == ERROR_SUCCESS)
125             error = regKey.SetDword(TEXT("Enable"), !!(dwFlags & 4));
126     }
127 
128     return ((error == ERROR_SUCCESS) ? S_OK : E_FAIL);
129 }
130 
131 /***********************************************************************
132  *      TF_UnregisterLangBarAddIn (MSCTF.@)
133  *
134  * @implemented
135  */
136 EXTERN_C HRESULT WINAPI
137 TF_UnregisterLangBarAddIn(
138     _In_ REFGUID rguid,
139     _In_ DWORD dwFlags)
140 {
141     TRACE("(%s, 0x%lX)\n", debugstr_guid(&rguid), dwFlags);
142 
143     if (IsEqualGUID(rguid, GUID_NULL))
144     {
145         ERR("E_INVALIDARG\n");
146         return E_INVALIDARG;
147     }
148 
149     TCHAR szSubKey[MAX_PATH];
150     StringCchCopy(szSubKey, _countof(szSubKey), TEXT("SOFTWARE\\Microsoft\\CTF\\LangBarAddIn\\"));
151 
152     CicRegKey regKey;
153     HKEY hBaseKey = ((dwFlags & 1) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
154     LSTATUS error = regKey.Open(hBaseKey, szSubKey, KEY_ALL_ACCESS);
155     HRESULT hr = E_FAIL;
156     if (error == ERROR_SUCCESS)
157     {
158         TCHAR szGUID[40];
159         StringFromGUID2T(rguid, szGUID, _countof(szGUID));
160         regKey.RecurseDeleteKey(szGUID);
161         hr = S_OK;
162     }
163 
164     return hr;
165 }
166 
167 /***********************************************************************
168  *      TF_RunInputCPL (MSCTF.@)
169  *
170  * @implemented
171  */
172 EXTERN_C HRESULT WINAPI
173 TF_RunInputCPL(VOID)
174 {
175     CicSystemModulePath ModPath;
176     TCHAR szCmdLine[2 * MAX_PATH];
177 
178     TRACE("()\n");
179 
180     // NOTE: We don't support Win95/98/Me
181     if (g_dwOSInfo & CIC_OSINFO_XPPLUS)
182         ModPath.Init(TEXT("input.dll"), FALSE);
183     else
184         ModPath.Init(TEXT("input.cpl"), FALSE);
185 
186     if (!ModPath.m_cchPath)
187         return E_FAIL;
188 
189     StringCchPrintf(szCmdLine, _countof(szCmdLine),
190                     TEXT("rundll32.exe shell32.dll,Control_RunDLL %s"), ModPath.m_szPath);
191     if (!RunCPLSetting(szCmdLine))
192         return E_FAIL;
193 
194     return S_OK;
195 }
196