1 /* 2 * PROJECT: ReactOS shlwapi 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: Implement SHAutoComplete 5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 */ 7 #include <windef.h> 8 #include <shlobj.h> 9 #include <shlwapi.h> 10 #include <browseui_undoc.h> 11 #include <shlwapi_undoc.h> 12 #include <shlguid_undoc.h> 13 #include <atlbase.h> 14 #include <atlcom.h> 15 #include <wine/debug.h> 16 17 WINE_DEFAULT_DEBUG_CHANNEL(shell); 18 19 static HRESULT 20 AutoComplete_AddMRU(CComPtr<IObjMgr> pManager, LPCWSTR pszKey) 21 { 22 CComPtr<IACLCustomMRU> pMRU; // Create an MRU list 23 HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_INPROC_SERVER, 24 IID_IACLCustomMRU, (LPVOID *)&pMRU); 25 if (FAILED(hr)) 26 { 27 ERR("CoCreateInstance(CLSID_ACLMRU) failed with 0x%08lX\n", hr); 28 return hr; 29 } 30 31 hr = pMRU->Initialize(pszKey, 'z' - 'a' + 1); // Load the list from registry 32 if (FAILED(hr)) 33 { 34 ERR("pMRU->Initialize(%ls) failed with 0x%08lX\n", pszKey, hr); 35 return hr; 36 } 37 38 hr = pManager->Append(pMRU); // Add to the manager 39 if (FAILED(hr)) 40 ERR("pManager->Append for '%ls' failed with 0x%08lX\n", pszKey, hr); 41 return hr; 42 } 43 44 static HRESULT 45 IUnknown_AddOptions(CComPtr<IUnknown> punk, DWORD dwACLO) 46 { 47 CComPtr<IACList2> pList; 48 HRESULT hr = punk->QueryInterface(IID_IACList2, (LPVOID *)&pList); 49 if (FAILED(hr)) 50 { 51 ERR("punk->QueryInterface failed: 0x%08lX\n", hr); 52 return hr; 53 } 54 55 DWORD dwOptions = 0; 56 pList->GetOptions(&dwOptions); 57 dwOptions |= dwACLO; 58 hr = pList->SetOptions(dwOptions); 59 if (FAILED(hr)) 60 ERR("pList->SetOptions failed: 0x%08lX\n", hr); 61 return hr; 62 } 63 64 static CComPtr<IUnknown> 65 AutoComplete_LoadList(DWORD dwSHACF, DWORD dwACLO) 66 { 67 // Create a multiple list (with IEnumString interface) 68 CComPtr<IUnknown> pList; 69 HRESULT hr = CoCreateInstance(CLSID_ACLMulti, NULL, CLSCTX_INPROC_SERVER, 70 IID_IUnknown, (LPVOID *)&pList); 71 if (FAILED(hr)) // Failed to create the list 72 { 73 ERR("CoCreateInstance(CLSID_ACLMulti) failed with 0x%08lX\n", hr); 74 return NULL; 75 } 76 77 CComPtr<IObjMgr> pManager; // This is the manager of the multiple list 78 hr = pList->QueryInterface(IID_IObjMgr, (LPVOID *)&pManager); 79 if (FAILED(hr)) // Failed to get interface 80 { 81 ERR("pList->QueryInterface failed: 0x%08lX\n", hr); 82 return NULL; 83 } 84 85 if (dwSHACF & SHACF_URLMRU) 86 { 87 // The MRU (Most-Recently-Used) lists (with IEnumString interface) 88 #define RUN_MRU_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU" 89 #define TYPED_URLS_KEY L"Software\\Microsoft\\Internet Explorer\\TypedURLs" 90 AutoComplete_AddMRU(pManager, RUN_MRU_KEY); 91 AutoComplete_AddMRU(pManager, TYPED_URLS_KEY); 92 } 93 94 if (dwSHACF & SHACF_URLHISTORY) 95 { 96 // The history list (with IEnumString interface) 97 CComPtr<IUnknown> pHistory; 98 hr = CoCreateInstance(CLSID_ACLHistory, NULL, CLSCTX_INPROC_SERVER, 99 IID_IUnknown, (LPVOID *)&pHistory); 100 if (SUCCEEDED(hr)) 101 { 102 pManager->Append(pHistory); // Add to the manager 103 // Add ACLO_* options 104 IUnknown_AddOptions(pHistory, dwACLO); 105 } 106 else 107 { 108 ERR("CLSID_ACLHistory hr:%08lX\n", hr); 109 } 110 } 111 112 if (dwSHACF & (SHACF_FILESYSTEM | SHACF_FILESYS_ONLY | SHACF_FILESYS_DIRS)) 113 { 114 // The filesystem list (with IEnumString interface) 115 CComPtr<IUnknown> pISF; 116 hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_INPROC_SERVER, 117 IID_IUnknown, (LPVOID *)&pISF); 118 if (SUCCEEDED(hr)) 119 { 120 pManager->Append(pISF); // Add to the manager 121 // Add ACLO_* options 122 IUnknown_AddOptions(pISF, dwACLO); 123 } 124 else 125 { 126 ERR("CLSID_ACListISF hr:%08lX\n", hr); 127 } 128 } 129 130 return pList; // The list 131 } 132 133 static VOID 134 AutoComplete_AdaptFlags(IN HWND hwndEdit, 135 IN OUT LPDWORD pdwSHACF, 136 OUT LPDWORD pdwACO, 137 OUT LPDWORD pdwACLO) 138 { 139 #define AUTOCOMPLETE_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete" 140 DWORD dwSHACF = *pdwSHACF, dwACO = 0, dwACLO = 0; 141 if (dwSHACF == SHACF_DEFAULT) 142 dwSHACF = SHACF_FILESYSTEM | SHACF_URLALL; 143 144 if (!(dwSHACF & SHACF_AUTOAPPEND_FORCE_OFF) && 145 ((dwSHACF & SHACF_AUTOAPPEND_FORCE_ON) || 146 SHRegGetBoolUSValueW(AUTOCOMPLETE_KEY, L"Append Completion", FALSE, FALSE))) 147 { 148 dwACO |= ACO_AUTOAPPEND; 149 } 150 151 if (!(dwSHACF & SHACF_AUTOSUGGEST_FORCE_OFF) && 152 ((dwSHACF & SHACF_AUTOSUGGEST_FORCE_ON) || 153 SHRegGetBoolUSValueW(AUTOCOMPLETE_KEY, L"AutoSuggest", FALSE, TRUE))) 154 { 155 dwACO |= ACO_AUTOSUGGEST; 156 } 157 158 if (dwSHACF & SHACF_FILESYS_DIRS) 159 dwACLO |= ACLO_FILESYSDIRS; 160 if (dwSHACF & SHACF_FILESYS_ONLY) 161 dwACLO |= ACLO_FILESYSONLY; 162 163 static BOOL s_bAlwaysUseTab = 99; 164 if (s_bAlwaysUseTab == 99) 165 s_bAlwaysUseTab = SHRegGetBoolUSValueW(AUTOCOMPLETE_KEY, L"Always Use Tab", FALSE, FALSE); 166 167 if (s_bAlwaysUseTab || (dwSHACF & SHACF_USETAB)) 168 dwACO |= ACO_USETAB; 169 170 if (GetWindowLongPtrW(hwndEdit, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) 171 dwACO |= ACO_RTLREADING; 172 173 *pdwSHACF = dwSHACF; 174 *pdwACO = dwACO; 175 *pdwACLO = dwACLO; 176 } 177 178 /************************************************************************* 179 * SHAutoComplete [SHLWAPI.@] 180 * 181 * Enable auto-completion for an edit control. 182 * 183 * PARAMS 184 * hwndEdit [I] Handle of control to enable auto-completion for 185 * dwFlags [I] SHACF_ flags from "shlwapi.h" 186 * 187 * RETURNS 188 * Success: S_OK. Auto-completion is enabled for the control. 189 * Failure: An HRESULT error code indicating the error. 190 */ 191 HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags) 192 { 193 TRACE("SHAutoComplete(%p, 0x%lX)\n", hwndEdit, dwFlags); 194 195 DWORD dwSHACF = dwFlags, dwACO = 0, dwACLO = 0; 196 AutoComplete_AdaptFlags(hwndEdit, &dwSHACF, &dwACO, &dwACLO); 197 198 // Load the list (with IEnumString interface) 199 CComPtr<IUnknown> pList = AutoComplete_LoadList(dwSHACF, dwACLO); 200 if (!pList) 201 { 202 ERR("Out of memory\n"); 203 return E_OUTOFMEMORY; 204 } 205 206 // Create an auto-completion (IAutoComplete2) 207 CComPtr<IAutoComplete2> pAC2; 208 HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, 209 IID_IAutoComplete2, (LPVOID *)&pAC2); 210 if (FAILED(hr)) 211 { 212 ERR("CoCreateInstance(CLSID_AutoComplete) failed: 0x%lX\n", hr); 213 return hr; 214 } 215 216 // Keep the DLLs of CLSID_ACListISF and CLSID_AutoComplete loaded 217 hr = E_FAIL; 218 if (SHPinDllOfCLSID(CLSID_ACListISF) && SHPinDllOfCLSID(CLSID_AutoComplete)) 219 { 220 // Initialize IAutoComplete2 for auto-completion 221 hr = pAC2->Init(hwndEdit, pList, NULL, NULL); 222 if (SUCCEEDED(hr)) 223 pAC2->SetOptions(dwACO); // Set ACO_* flags 224 else 225 ERR("IAutoComplete2::Init failed: 0x%lX\n", hr); 226 } 227 228 return hr; 229 } 230