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