2 * PROJECT: ReactOS browseui
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Custom MRU AutoComplete List
5 * COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
6 * Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
11 #define TYPED_URLS_KEY L"Software\\Microsoft\\Internet Explorer\\TypedURLs"
13 CACLCustomMRU::CACLCustomMRU()
14 : m_bDirty(false), m_bTypedURLs(FALSE
), m_ielt(0)
18 CACLCustomMRU::~CACLCustomMRU()
23 STDMETHODIMP
CACLCustomMRU::Next(ULONG celt
, LPWSTR
*rgelt
, ULONG
*pceltFetched
)
25 if (!pceltFetched
|| !rgelt
)
33 if (INT(m_ielt
) >= m_MRUData
.GetSize())
36 CStringW str
= m_MRUData
[m_ielt
];
40 // Erase the last "\\1" etc. (indicates SW_* value)
41 INT ich
= str
.ReverseFind(L
'\\');
46 size_t cb
= (str
.GetLength() + 1) * sizeof(WCHAR
);
47 LPWSTR psz
= (LPWSTR
)CoTaskMemAlloc(cb
);
51 CopyMemory(psz
, (LPCWSTR
)str
, cb
);
58 STDMETHODIMP
CACLCustomMRU::Skip(ULONG celt
)
63 STDMETHODIMP
CACLCustomMRU::Reset()
69 STDMETHODIMP
CACLCustomMRU::Clone(IEnumString
** ppenum
)
75 STDMETHODIMP
CACLCustomMRU::Expand(LPCOLESTR pszExpand
)
80 void CACLCustomMRU::PersistMRU()
82 if (!m_bDirty
|| m_bTypedURLs
)
85 WCHAR Key
[2] = { 0, 0 };
91 m_Key
.SetStringValue(L
"MRUList", m_MRUList
);
92 for (int Index
= 0; Index
< m_MRUList
.GetLength(); ++Index
)
95 m_Key
.SetStringValue(Key
, m_MRUData
[Index
]);
101 RegQueryCStringW(CRegKey
& key
, LPCWSTR pszValueName
, CStringW
& str
)
103 // Check type and size
104 DWORD dwType
, cbData
;
105 LSTATUS ret
= key
.QueryValue(pszValueName
, &dwType
, NULL
, &cbData
);
106 if (ret
!= ERROR_SUCCESS
)
108 if (dwType
!= REG_SZ
&& dwType
!= REG_EXPAND_SZ
)
109 return ERROR_INVALID_DATA
;
112 LPWSTR pszBuffer
= str
.GetBuffer(cbData
/ sizeof(WCHAR
) + 1);
113 if (pszBuffer
== NULL
)
114 return ERROR_OUTOFMEMORY
;
117 ret
= key
.QueryValue(pszValueName
, NULL
, pszBuffer
, &cbData
);
124 HRESULT
CACLCustomMRU::LoadTypedURLs(DWORD dwMax
)
126 dwMax
= max(0, dwMax
);
127 dwMax
= min(29, dwMax
);
132 for (DWORD i
= 1; i
<= dwMax
; ++i
)
134 // Build a registry value name
135 StringCbPrintfW(szName
, sizeof(szName
), L
"url%lu", i
);
137 // Read a registry value
138 status
= RegQueryCStringW(m_Key
, szName
, strData
);
139 if (status
!= ERROR_SUCCESS
)
142 m_MRUData
.Add(strData
);
148 // *** IACLCustomMRU methods ***
149 HRESULT STDMETHODCALLTYPE
CACLCustomMRU::Initialize(LPCWSTR pwszMRURegKey
, DWORD dwMax
)
153 LSTATUS Status
= m_Key
.Create(HKEY_CURRENT_USER
, pwszMRURegKey
);
154 if (Status
!= ERROR_SUCCESS
)
155 return HRESULT_FROM_WIN32(Status
);
157 m_MRUData
.RemoveAll();
158 if (lstrcmpiW(pwszMRURegKey
, TYPED_URLS_KEY
) == 0)
161 return LoadTypedURLs(dwMax
);
165 m_bTypedURLs
= FALSE
;
166 return LoadMRUList(dwMax
);
170 HRESULT
CACLCustomMRU::LoadMRUList(DWORD dwMax
)
172 dwMax
= max(0, dwMax
);
173 dwMax
= min(29, dwMax
);
175 m_MRUData
.Add(CStringW());
178 ULONG nChars
= _countof(MRUList
);
180 LSTATUS Status
= m_Key
.QueryStringValue(L
"MRUList", MRUList
, &nChars
);
181 if (Status
!= ERROR_SUCCESS
)
184 if (nChars
> 0 && MRUList
[nChars
-1] == '\0')
187 if (nChars
> (ULONG
)m_MRUData
.GetSize())
190 for (ULONG n
= 0; n
< nChars
; ++n
)
192 if (MRUList
[n
] >= 'a' && MRUList
[n
] <= '}' && m_MRUList
.Find(MRUList
[n
]) < 0)
194 WCHAR Key
[2] = { MRUList
[n
], NULL
};
195 WCHAR Value
[MAX_PATH
* 2];
196 ULONG nValueChars
= _countof(Value
);
198 m_MRUList
+= MRUList
[n
];
199 int Index
= MRUList
[n
] - 'a';
201 if (Index
< m_MRUData
.GetSize())
203 Status
= m_Key
.QueryStringValue(Key
, Value
, &nValueChars
);
204 if (Status
== ERROR_SUCCESS
)
206 m_MRUData
[Index
] = CStringW(Value
, nValueChars
);
215 HRESULT STDMETHODCALLTYPE
CACLCustomMRU::AddMRUString(LPCWSTR pwszEntry
)
220 ATLASSERT(m_MRUData
.GetSize() <= m_MRUList
.GetLength());
223 CStringW NewElement
= pwszEntry
;
224 WCHAR Key
[2] = { 0, 0 };
225 int Index
= m_MRUData
.Find(NewElement
);
228 /* Move the key to the front */
229 Key
[0] = Index
+ 'a';
230 m_MRUList
.Replace(Key
, L
"");
231 m_MRUList
= Key
+ m_MRUList
;
235 int TotalLen
= m_MRUList
.GetLength();
236 if (m_MRUData
.GetSize() == TotalLen
)
238 /* Find oldest element, move that to the front */
239 Key
[0] = m_MRUList
[TotalLen
-1];
240 m_MRUList
= Key
+ m_MRUList
.Left(TotalLen
-1);
241 Index
= Key
[0] - 'a';
245 /* Find the first empty entry */
246 for (Index
= 0; Index
< m_MRUData
.GetSize(); ++Index
)
248 if (m_MRUData
[Index
].IsEmpty())
251 Key
[0] = Index
+ 'a';
252 m_MRUList
= Key
+ m_MRUList
;
254 m_MRUData
[Index
] = NewElement
;