1ad181d89SMark Jansen /*
2ad181d89SMark Jansen * PROJECT: ReactOS browseui
3ad181d89SMark Jansen * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4ad181d89SMark Jansen * PURPOSE: Custom MRU AutoComplete List
5ad181d89SMark Jansen * COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
6bb8cb671SKatayama Hirofumi MZ * Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7ad181d89SMark Jansen */
8ad181d89SMark Jansen
9ad181d89SMark Jansen #include "precomp.h"
10ad181d89SMark Jansen
11bb8cb671SKatayama Hirofumi MZ #define TYPED_URLS_KEY L"Software\\Microsoft\\Internet Explorer\\TypedURLs"
12bb8cb671SKatayama Hirofumi MZ
CACLCustomMRU()13ad181d89SMark Jansen CACLCustomMRU::CACLCustomMRU()
14bb8cb671SKatayama Hirofumi MZ : m_bDirty(false), m_bTypedURLs(FALSE), m_ielt(0)
15ad181d89SMark Jansen {
16ad181d89SMark Jansen }
17ad181d89SMark Jansen
~CACLCustomMRU()18ad181d89SMark Jansen CACLCustomMRU::~CACLCustomMRU()
19ad181d89SMark Jansen {
20ad181d89SMark Jansen PersistMRU();
21bb8cb671SKatayama Hirofumi MZ }
22bb8cb671SKatayama Hirofumi MZ
Next(ULONG celt,LPWSTR * rgelt,ULONG * pceltFetched)23bb8cb671SKatayama Hirofumi MZ STDMETHODIMP CACLCustomMRU::Next(ULONG celt, LPWSTR *rgelt, ULONG *pceltFetched)
24bb8cb671SKatayama Hirofumi MZ {
25bb8cb671SKatayama Hirofumi MZ if (!pceltFetched || !rgelt)
26bb8cb671SKatayama Hirofumi MZ return E_POINTER;
27bb8cb671SKatayama Hirofumi MZ
28bb8cb671SKatayama Hirofumi MZ *pceltFetched = 0;
29bb8cb671SKatayama Hirofumi MZ if (celt == 0)
30bb8cb671SKatayama Hirofumi MZ return S_OK;
31bb8cb671SKatayama Hirofumi MZ
32bb8cb671SKatayama Hirofumi MZ *rgelt = NULL;
33bb8cb671SKatayama Hirofumi MZ if (INT(m_ielt) >= m_MRUData.GetSize())
34bb8cb671SKatayama Hirofumi MZ return S_FALSE;
35bb8cb671SKatayama Hirofumi MZ
36*957d0743SKatayama Hirofumi MZ CStringW str = m_MRUData[m_ielt];
37*957d0743SKatayama Hirofumi MZ
38*957d0743SKatayama Hirofumi MZ if (!m_bTypedURLs)
39*957d0743SKatayama Hirofumi MZ {
40*957d0743SKatayama Hirofumi MZ // Erase the last "\\1" etc. (indicates SW_* value)
41*957d0743SKatayama Hirofumi MZ INT ich = str.ReverseFind(L'\\');
42*957d0743SKatayama Hirofumi MZ if (ich >= 0)
43*957d0743SKatayama Hirofumi MZ str = str.Left(ich);
44*957d0743SKatayama Hirofumi MZ }
45*957d0743SKatayama Hirofumi MZ
46*957d0743SKatayama Hirofumi MZ size_t cb = (str.GetLength() + 1) * sizeof(WCHAR);
47bb8cb671SKatayama Hirofumi MZ LPWSTR psz = (LPWSTR)CoTaskMemAlloc(cb);
48bb8cb671SKatayama Hirofumi MZ if (!psz)
49bb8cb671SKatayama Hirofumi MZ return S_FALSE;
50bb8cb671SKatayama Hirofumi MZ
51*957d0743SKatayama Hirofumi MZ CopyMemory(psz, (LPCWSTR)str, cb);
52bb8cb671SKatayama Hirofumi MZ *rgelt = psz;
53bb8cb671SKatayama Hirofumi MZ *pceltFetched = 1;
54bb8cb671SKatayama Hirofumi MZ ++m_ielt;
55bb8cb671SKatayama Hirofumi MZ return S_OK;
56bb8cb671SKatayama Hirofumi MZ }
57bb8cb671SKatayama Hirofumi MZ
Skip(ULONG celt)58bb8cb671SKatayama Hirofumi MZ STDMETHODIMP CACLCustomMRU::Skip(ULONG celt)
59bb8cb671SKatayama Hirofumi MZ {
60bb8cb671SKatayama Hirofumi MZ return E_NOTIMPL;
61bb8cb671SKatayama Hirofumi MZ }
62bb8cb671SKatayama Hirofumi MZ
Reset()63bb8cb671SKatayama Hirofumi MZ STDMETHODIMP CACLCustomMRU::Reset()
64bb8cb671SKatayama Hirofumi MZ {
65bb8cb671SKatayama Hirofumi MZ m_ielt = 0;
66bb8cb671SKatayama Hirofumi MZ return S_OK;
67bb8cb671SKatayama Hirofumi MZ }
68bb8cb671SKatayama Hirofumi MZ
Clone(IEnumString ** ppenum)69bb8cb671SKatayama Hirofumi MZ STDMETHODIMP CACLCustomMRU::Clone(IEnumString ** ppenum)
70bb8cb671SKatayama Hirofumi MZ {
71bb8cb671SKatayama Hirofumi MZ *ppenum = NULL;
72bb8cb671SKatayama Hirofumi MZ return E_NOTIMPL;
73bb8cb671SKatayama Hirofumi MZ }
74bb8cb671SKatayama Hirofumi MZ
Expand(LPCOLESTR pszExpand)75bb8cb671SKatayama Hirofumi MZ STDMETHODIMP CACLCustomMRU::Expand(LPCOLESTR pszExpand)
76bb8cb671SKatayama Hirofumi MZ {
77bb8cb671SKatayama Hirofumi MZ return E_NOTIMPL;
78ad181d89SMark Jansen }
79ad181d89SMark Jansen
PersistMRU()80ad181d89SMark Jansen void CACLCustomMRU::PersistMRU()
81ad181d89SMark Jansen {
82bb8cb671SKatayama Hirofumi MZ if (!m_bDirty || m_bTypedURLs)
83bb8cb671SKatayama Hirofumi MZ return;
84bb8cb671SKatayama Hirofumi MZ
85ad181d89SMark Jansen WCHAR Key[2] = { 0, 0 };
86ad181d89SMark Jansen
87ad181d89SMark Jansen m_bDirty = false;
88ad181d89SMark Jansen
89ad181d89SMark Jansen if (m_Key.m_hKey)
90ad181d89SMark Jansen {
91ad181d89SMark Jansen m_Key.SetStringValue(L"MRUList", m_MRUList);
92ad181d89SMark Jansen for (int Index = 0; Index < m_MRUList.GetLength(); ++Index)
93ad181d89SMark Jansen {
94ad181d89SMark Jansen Key[0] = Index + 'a';
95ad181d89SMark Jansen m_Key.SetStringValue(Key, m_MRUData[Index]);
96ad181d89SMark Jansen }
97ad181d89SMark Jansen }
98ad181d89SMark Jansen }
99ad181d89SMark Jansen
100bb8cb671SKatayama Hirofumi MZ static LSTATUS
RegQueryCStringW(CRegKey & key,LPCWSTR pszValueName,CStringW & str)101bb8cb671SKatayama Hirofumi MZ RegQueryCStringW(CRegKey& key, LPCWSTR pszValueName, CStringW& str)
102bb8cb671SKatayama Hirofumi MZ {
103bb8cb671SKatayama Hirofumi MZ // Check type and size
104bb8cb671SKatayama Hirofumi MZ DWORD dwType, cbData;
105bb8cb671SKatayama Hirofumi MZ LSTATUS ret = key.QueryValue(pszValueName, &dwType, NULL, &cbData);
106bb8cb671SKatayama Hirofumi MZ if (ret != ERROR_SUCCESS)
107bb8cb671SKatayama Hirofumi MZ return ret;
108bb8cb671SKatayama Hirofumi MZ if (dwType != REG_SZ && dwType != REG_EXPAND_SZ)
109bb8cb671SKatayama Hirofumi MZ return ERROR_INVALID_DATA;
110bb8cb671SKatayama Hirofumi MZ
111bb8cb671SKatayama Hirofumi MZ // Allocate buffer
112bb8cb671SKatayama Hirofumi MZ LPWSTR pszBuffer = str.GetBuffer(cbData / sizeof(WCHAR) + 1);
113bb8cb671SKatayama Hirofumi MZ if (pszBuffer == NULL)
114bb8cb671SKatayama Hirofumi MZ return ERROR_OUTOFMEMORY;
115bb8cb671SKatayama Hirofumi MZ
116bb8cb671SKatayama Hirofumi MZ // Get the data
117bb8cb671SKatayama Hirofumi MZ ret = key.QueryValue(pszValueName, NULL, pszBuffer, &cbData);
118bb8cb671SKatayama Hirofumi MZ
119bb8cb671SKatayama Hirofumi MZ // Release buffer
120bb8cb671SKatayama Hirofumi MZ str.ReleaseBuffer();
121bb8cb671SKatayama Hirofumi MZ return ret;
122bb8cb671SKatayama Hirofumi MZ }
123bb8cb671SKatayama Hirofumi MZ
LoadTypedURLs(DWORD dwMax)124bb8cb671SKatayama Hirofumi MZ HRESULT CACLCustomMRU::LoadTypedURLs(DWORD dwMax)
125bb8cb671SKatayama Hirofumi MZ {
126bb8cb671SKatayama Hirofumi MZ dwMax = max(0, dwMax);
127bb8cb671SKatayama Hirofumi MZ dwMax = min(29, dwMax);
128bb8cb671SKatayama Hirofumi MZ
129bb8cb671SKatayama Hirofumi MZ WCHAR szName[32];
130bb8cb671SKatayama Hirofumi MZ CStringW strData;
131bb8cb671SKatayama Hirofumi MZ LSTATUS status;
132bb8cb671SKatayama Hirofumi MZ for (DWORD i = 1; i <= dwMax; ++i)
133bb8cb671SKatayama Hirofumi MZ {
134bb8cb671SKatayama Hirofumi MZ // Build a registry value name
135bb8cb671SKatayama Hirofumi MZ StringCbPrintfW(szName, sizeof(szName), L"url%lu", i);
136bb8cb671SKatayama Hirofumi MZ
137bb8cb671SKatayama Hirofumi MZ // Read a registry value
138bb8cb671SKatayama Hirofumi MZ status = RegQueryCStringW(m_Key, szName, strData);
139bb8cb671SKatayama Hirofumi MZ if (status != ERROR_SUCCESS)
140bb8cb671SKatayama Hirofumi MZ break;
141bb8cb671SKatayama Hirofumi MZ
142bb8cb671SKatayama Hirofumi MZ m_MRUData.Add(strData);
143bb8cb671SKatayama Hirofumi MZ }
144bb8cb671SKatayama Hirofumi MZ
145bb8cb671SKatayama Hirofumi MZ return S_OK;
146bb8cb671SKatayama Hirofumi MZ }
147bb8cb671SKatayama Hirofumi MZ
148ad181d89SMark Jansen // *** IACLCustomMRU methods ***
Initialize(LPCWSTR pwszMRURegKey,DWORD dwMax)149ad181d89SMark Jansen HRESULT STDMETHODCALLTYPE CACLCustomMRU::Initialize(LPCWSTR pwszMRURegKey, DWORD dwMax)
150ad181d89SMark Jansen {
151bb8cb671SKatayama Hirofumi MZ m_ielt = 0;
152bb8cb671SKatayama Hirofumi MZ
153ad181d89SMark Jansen LSTATUS Status = m_Key.Create(HKEY_CURRENT_USER, pwszMRURegKey);
154ad181d89SMark Jansen if (Status != ERROR_SUCCESS)
155ad181d89SMark Jansen return HRESULT_FROM_WIN32(Status);
156ad181d89SMark Jansen
157ad181d89SMark Jansen m_MRUData.RemoveAll();
158bb8cb671SKatayama Hirofumi MZ if (lstrcmpiW(pwszMRURegKey, TYPED_URLS_KEY) == 0)
159bb8cb671SKatayama Hirofumi MZ {
160bb8cb671SKatayama Hirofumi MZ m_bTypedURLs = TRUE;
161bb8cb671SKatayama Hirofumi MZ return LoadTypedURLs(dwMax);
162bb8cb671SKatayama Hirofumi MZ }
163bb8cb671SKatayama Hirofumi MZ else
164bb8cb671SKatayama Hirofumi MZ {
165bb8cb671SKatayama Hirofumi MZ m_bTypedURLs = FALSE;
166bb8cb671SKatayama Hirofumi MZ return LoadMRUList(dwMax);
167bb8cb671SKatayama Hirofumi MZ }
168bb8cb671SKatayama Hirofumi MZ }
169bb8cb671SKatayama Hirofumi MZ
LoadMRUList(DWORD dwMax)170bb8cb671SKatayama Hirofumi MZ HRESULT CACLCustomMRU::LoadMRUList(DWORD dwMax)
171bb8cb671SKatayama Hirofumi MZ {
172ad181d89SMark Jansen dwMax = max(0, dwMax);
173ad181d89SMark Jansen dwMax = min(29, dwMax);
174ad181d89SMark Jansen while (dwMax--)
175ad181d89SMark Jansen m_MRUData.Add(CStringW());
176ad181d89SMark Jansen
177ad181d89SMark Jansen WCHAR MRUList[40];
178ad181d89SMark Jansen ULONG nChars = _countof(MRUList);
179ad181d89SMark Jansen
180bb8cb671SKatayama Hirofumi MZ LSTATUS Status = m_Key.QueryStringValue(L"MRUList", MRUList, &nChars);
181ad181d89SMark Jansen if (Status != ERROR_SUCCESS)
182ad181d89SMark Jansen return S_OK;
183ad181d89SMark Jansen
184ad181d89SMark Jansen if (nChars > 0 && MRUList[nChars-1] == '\0')
185ad181d89SMark Jansen nChars--;
186ad181d89SMark Jansen
187ad181d89SMark Jansen if (nChars > (ULONG)m_MRUData.GetSize())
188ad181d89SMark Jansen return S_OK;
189ad181d89SMark Jansen
190ad181d89SMark Jansen for (ULONG n = 0; n < nChars; ++n)
191ad181d89SMark Jansen {
192ad181d89SMark Jansen if (MRUList[n] >= 'a' && MRUList[n] <= '}' && m_MRUList.Find(MRUList[n]) < 0)
193ad181d89SMark Jansen {
194ad181d89SMark Jansen WCHAR Key[2] = { MRUList[n], NULL };
195ad181d89SMark Jansen WCHAR Value[MAX_PATH * 2];
196ad181d89SMark Jansen ULONG nValueChars = _countof(Value);
197ad181d89SMark Jansen
198ad181d89SMark Jansen m_MRUList += MRUList[n];
199ad181d89SMark Jansen int Index = MRUList[n] - 'a';
200ad181d89SMark Jansen
201ad181d89SMark Jansen if (Index < m_MRUData.GetSize())
202ad181d89SMark Jansen {
203ad181d89SMark Jansen Status = m_Key.QueryStringValue(Key, Value, &nValueChars);
204ad181d89SMark Jansen if (Status == ERROR_SUCCESS)
205ad181d89SMark Jansen {
206ad181d89SMark Jansen m_MRUData[Index] = CStringW(Value, nValueChars);
207ad181d89SMark Jansen }
208ad181d89SMark Jansen }
209ad181d89SMark Jansen }
210ad181d89SMark Jansen }
211ad181d89SMark Jansen
212ad181d89SMark Jansen return S_OK;
213ad181d89SMark Jansen }
214ad181d89SMark Jansen
AddMRUString(LPCWSTR pwszEntry)215ad181d89SMark Jansen HRESULT STDMETHODCALLTYPE CACLCustomMRU::AddMRUString(LPCWSTR pwszEntry)
216ad181d89SMark Jansen {
217bb8cb671SKatayama Hirofumi MZ if (m_bTypedURLs)
218bb8cb671SKatayama Hirofumi MZ return E_FAIL;
219bb8cb671SKatayama Hirofumi MZ
22014c18657SHirofumi Katayama ATLASSERT(m_MRUData.GetSize() <= m_MRUList.GetLength());
221ad181d89SMark Jansen m_bDirty = true;
222ad181d89SMark Jansen
223ad181d89SMark Jansen CStringW NewElement = pwszEntry;
224ad181d89SMark Jansen WCHAR Key[2] = { 0, 0 };
225ad181d89SMark Jansen int Index = m_MRUData.Find(NewElement);
226ad181d89SMark Jansen if (Index >= 0)
227ad181d89SMark Jansen {
228ad181d89SMark Jansen /* Move the key to the front */
229ad181d89SMark Jansen Key[0] = Index + 'a';
230ad181d89SMark Jansen m_MRUList.Replace(Key, L"");
231ad181d89SMark Jansen m_MRUList = Key + m_MRUList;
232ad181d89SMark Jansen return S_OK;
233ad181d89SMark Jansen }
234ad181d89SMark Jansen
235ad181d89SMark Jansen int TotalLen = m_MRUList.GetLength();
236ad181d89SMark Jansen if (m_MRUData.GetSize() == TotalLen)
237ad181d89SMark Jansen {
238ad181d89SMark Jansen /* Find oldest element, move that to the front */
239ad181d89SMark Jansen Key[0] = m_MRUList[TotalLen-1];
240ad181d89SMark Jansen m_MRUList = Key + m_MRUList.Left(TotalLen-1);
241ad181d89SMark Jansen Index = Key[0] - 'a';
242ad181d89SMark Jansen }
243ad181d89SMark Jansen else
244ad181d89SMark Jansen {
245ad181d89SMark Jansen /* Find the first empty entry */
246ad181d89SMark Jansen for (Index = 0; Index < m_MRUData.GetSize(); ++Index)
247ad181d89SMark Jansen {
248ad181d89SMark Jansen if (m_MRUData[Index].IsEmpty())
249ad181d89SMark Jansen break;
250ad181d89SMark Jansen }
251ad181d89SMark Jansen Key[0] = Index + 'a';
252ad181d89SMark Jansen m_MRUList = Key + m_MRUList;
253ad181d89SMark Jansen }
254ad181d89SMark Jansen m_MRUData[Index] = NewElement;
255ad181d89SMark Jansen
256ad181d89SMark Jansen PersistMRU();
257ad181d89SMark Jansen return S_OK;
258ad181d89SMark Jansen }
259ad181d89SMark Jansen
260