1 /*
2 * PROJECT: ReactOS shdocvw
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Implement MRU List of shdocvw.dll
5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #define COBJMACROS
9
10 #include "objects.h"
11 #include <tchar.h>
12 #include <strsafe.h>
13
14 #include <wine/debug.h>
15 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
16
17 class CSafeMutex;
18 class CMruBase;
19 class CMruShortList;
20 class CMruLongList;
21 class CMruNode;
22 class CMruPidlList;
23 class CMruClassFactory;
24
25 // The flags for SLOTITEMDATA.dwFlags
26 #define SLOT_LOADED 0x1
27 #define SLOT_SET 0x2
28
29 // The flags for CMruBase.m_dwFlags
30 #define COMPARE_BY_MEMCMP 0x0
31 #define COMPARE_BY_STRCMPIW 0x1
32 #define COMPARE_BY_STRCMPW 0x2
33 #define COMPARE_BY_IEILISEQUAL 0x3
34 #define COMPARE_BY_MASK 0xF
35
36 class CSafeMutex
37 {
38 protected:
39 HANDLE m_hMutex;
40
41 public:
CSafeMutex()42 CSafeMutex() : m_hMutex(NULL)
43 {
44 }
~CSafeMutex()45 ~CSafeMutex()
46 {
47 if (m_hMutex)
48 {
49 ::ReleaseMutex(m_hMutex);
50 m_hMutex = NULL;
51 }
52 }
53
Enter(HANDLE hMutex)54 HRESULT Enter(HANDLE hMutex)
55 {
56 DWORD wait = ::WaitForSingleObject(hMutex, 500);
57 if (wait != WAIT_OBJECT_0)
58 return E_FAIL;
59
60 m_hMutex = hMutex;
61 return S_OK;
62 }
63 };
64
65 class CMruBase
66 : public IMruDataList
67 {
68 protected:
69 LONG m_cRefs = 1; // Reference count
70 DWORD m_dwFlags = 0; // The COMPARE_BY_... flags
71 BOOL m_bNeedSave = FALSE; // The flag that indicates whether it needs saving
72 BOOL m_bChecked = FALSE; // The checked flag
73 HKEY m_hKey = NULL; // A registry key
74 DWORD m_cSlotRooms = 0; // Rooms for slots
75 DWORD m_cSlots = 0; // The # of slots
76 SLOTCOMPARE m_fnCompare = NULL; // The comparison function
77 SLOTITEMDATA * m_pSlots = NULL; // Slot data
78
79 HRESULT _LoadItem(UINT iSlot);
80 HRESULT _AddItem(UINT iSlot, LPCVOID pvData, DWORD cbData);
81 HRESULT _GetItem(UINT iSlot, SLOTITEMDATA **ppItem);
82 void _DeleteItem(UINT iSlot);
83
84 HRESULT _GetSlotItem(UINT iSlot, SLOTITEMDATA **ppItem);
85 void _CheckUsedSlots();
86 HRESULT _UseEmptySlot(UINT *piSlot);
87
88 public:
89 CMruBase();
90 virtual ~CMruBase();
91
92 // IUnknown methods
93 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override;
AddRef()94 STDMETHODIMP_(ULONG) AddRef() override
95 {
96 return ::InterlockedIncrement(&m_cRefs);
97 }
98 STDMETHODIMP_(ULONG) Release() override;
99
100 // IMruDataList methods
101 STDMETHODIMP InitData(UINT cCapacity, UINT flags, HKEY hKey,
102 LPCWSTR pszSubKey OPTIONAL,
103 SLOTCOMPARE fnCompare OPTIONAL) override;
104 STDMETHODIMP AddData(LPCVOID pvData, DWORD cbData, UINT *piSlot) override;
105 STDMETHODIMP FindData(LPCVOID pvData, DWORD cbData, UINT *piSlot) override;
106 STDMETHODIMP GetData(UINT iSlot, LPVOID pvData, DWORD cbData) override;
107 STDMETHODIMP QueryInfo(UINT iSlot, UINT *piGotSlot, DWORD *pcbData) override;
108 STDMETHODIMP Delete(UINT iSlot) override;
109
110 // Non-standard methods
111 virtual BOOL _IsEqual(const SLOTITEMDATA *pItem, LPCVOID pvData, UINT cbData) const;
112 virtual DWORD _DeleteValue(LPCWSTR pszValue);
113 virtual HRESULT _InitSlots() = 0;
114 virtual void _SaveSlots() = 0;
115 virtual UINT _UpdateSlots(UINT iSlot) = 0;
116 virtual void _SlotString(UINT iSlot, LPWSTR psz, DWORD cch) = 0;
117 virtual HRESULT _GetSlot(UINT iSlot, UINT *puSlot) = 0;
118 virtual HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) = 0;
119
operator new(size_t size)120 static void* operator new(size_t size)
121 {
122 return ::LocalAlloc(LPTR, size);
123 }
operator delete(void * ptr)124 static void operator delete(void *ptr)
125 {
126 ::LocalFree(ptr);
127 }
128 };
129
CMruBase()130 CMruBase::CMruBase()
131 {
132 SHDOCVW_LockModule();
133 }
134
~CMruBase()135 CMruBase::~CMruBase()
136 {
137 if (m_hKey)
138 {
139 ::RegCloseKey(m_hKey);
140 m_hKey = NULL;
141 }
142
143 if (m_pSlots)
144 {
145 for (UINT iSlot = 0; iSlot < m_cSlots; ++iSlot)
146 {
147 m_pSlots[iSlot].pvData = ::LocalFree(m_pSlots[iSlot].pvData);
148 }
149
150 m_pSlots = (SLOTITEMDATA*)::LocalFree(m_pSlots);
151 }
152
153 SHDOCVW_UnlockModule();
154 }
155
QueryInterface(REFIID riid,void ** ppvObj)156 STDMETHODIMP CMruBase::QueryInterface(REFIID riid, void **ppvObj)
157 {
158 if (!ppvObj)
159 return E_POINTER;
160 if (IsEqualGUID(riid, IID_IMruDataList) || IsEqualGUID(riid, IID_IUnknown))
161 {
162 *ppvObj = static_cast<IMruDataList*>(this);
163 AddRef();
164 return S_OK;
165 }
166 ERR("%s: E_NOINTERFACE\n", debugstr_guid(&riid));
167 return E_NOINTERFACE;
168 }
169
STDMETHODIMP_(ULONG)170 STDMETHODIMP_(ULONG) CMruBase::Release()
171 {
172 if (::InterlockedDecrement(&m_cRefs) == 0)
173 {
174 _SaveSlots();
175 delete this;
176 return 0;
177 }
178 return m_cRefs;
179 }
180
_LoadItem(UINT iSlot)181 HRESULT CMruBase::_LoadItem(UINT iSlot)
182 {
183 DWORD cbData;
184 WCHAR szValue[12];
185
186 SLOTITEMDATA *pItem = &m_pSlots[iSlot];
187 _SlotString(iSlot, szValue, _countof(szValue));
188
189 if (SHGetValueW(m_hKey, NULL, szValue, NULL, NULL, &cbData) == ERROR_SUCCESS &&
190 cbData > 0)
191 {
192 pItem->pvData = ::LocalAlloc(LPTR, cbData);
193 if (pItem->pvData)
194 {
195 pItem->cbData = cbData;
196 if (SHGetValueW(m_hKey, NULL, szValue, NULL, pItem->pvData, &cbData) != ERROR_SUCCESS)
197 pItem->pvData = ::LocalFree(pItem->pvData);
198 }
199 }
200
201 pItem->dwFlags |= SLOT_LOADED;
202 if (!pItem->pvData)
203 return E_FAIL;
204
205 return S_OK;
206 }
207
_GetSlotItem(UINT iSlot,SLOTITEMDATA ** ppItem)208 HRESULT CMruBase::_GetSlotItem(UINT iSlot, SLOTITEMDATA **ppItem)
209 {
210 if (!(m_pSlots[iSlot].dwFlags & SLOT_LOADED))
211 _LoadItem(iSlot);
212
213 SLOTITEMDATA *pItem = &m_pSlots[iSlot];
214 if (!pItem->pvData)
215 return E_OUTOFMEMORY;
216
217 *ppItem = pItem;
218 return S_OK;
219 }
220
_GetItem(UINT iSlot,SLOTITEMDATA ** ppItem)221 HRESULT CMruBase::_GetItem(UINT iSlot, SLOTITEMDATA **ppItem)
222 {
223 HRESULT hr = _GetSlot(iSlot, &iSlot);
224 if (FAILED(hr))
225 return hr;
226 return _GetSlotItem(iSlot, ppItem);
227 }
228
_DeleteItem(UINT iSlot)229 void CMruBase::_DeleteItem(UINT iSlot)
230 {
231 WCHAR szBuff[12];
232
233 _SlotString(iSlot, szBuff, _countof(szBuff));
234 _DeleteValue(szBuff);
235
236 m_pSlots[iSlot].pvData = ::LocalFree(m_pSlots[iSlot].pvData);
237 }
238
_CheckUsedSlots()239 void CMruBase::_CheckUsedSlots()
240 {
241 UINT iGotSlot;
242 for (UINT iSlot = 0; iSlot < m_cSlots; ++iSlot)
243 _GetSlot(iSlot, &iGotSlot);
244
245 m_bChecked = TRUE;
246 }
247
_AddItem(UINT iSlot,LPCVOID pvData,DWORD cbData)248 HRESULT CMruBase::_AddItem(UINT iSlot, LPCVOID pvData, DWORD cbData)
249 {
250 SLOTITEMDATA *pItem = &m_pSlots[iSlot];
251
252 WCHAR szBuff[12];
253 _SlotString(iSlot, szBuff, _countof(szBuff));
254
255 if (SHSetValueW(m_hKey, NULL, szBuff, REG_BINARY, pvData, cbData) != ERROR_SUCCESS)
256 return E_OUTOFMEMORY;
257
258 if (cbData >= pItem->cbData || !pItem->pvData)
259 {
260 ::LocalFree(pItem->pvData);
261 pItem->pvData = ::LocalAlloc(LPTR, cbData);
262 }
263
264 if (!pItem->pvData)
265 return E_FAIL;
266
267 pItem->cbData = cbData;
268 pItem->dwFlags = (SLOT_LOADED | SLOT_SET);
269 CopyMemory(pItem->pvData, pvData, cbData);
270 return S_OK;
271 }
272
273 STDMETHODIMP
InitData(UINT cCapacity,UINT flags,HKEY hKey,LPCWSTR pszSubKey OPTIONAL,SLOTCOMPARE fnCompare OPTIONAL)274 CMruBase::InitData(
275 UINT cCapacity,
276 UINT flags,
277 HKEY hKey,
278 LPCWSTR pszSubKey OPTIONAL,
279 SLOTCOMPARE fnCompare OPTIONAL)
280 {
281 m_dwFlags = flags;
282 m_fnCompare = fnCompare;
283 m_cSlotRooms = cCapacity;
284
285 if (pszSubKey)
286 ::RegCreateKeyExWrapW(hKey, pszSubKey, 0, NULL, 0, MAXIMUM_ALLOWED, NULL, &m_hKey, NULL);
287 else
288 m_hKey = SHRegDuplicateHKey(hKey);
289
290 if (!m_hKey)
291 return E_FAIL;
292
293 m_pSlots = (SLOTITEMDATA*)::LocalAlloc(LPTR, m_cSlotRooms * sizeof(SLOTITEMDATA));
294 if (!m_pSlots)
295 return E_OUTOFMEMORY;
296
297 return _InitSlots();
298 }
299
AddData(LPCVOID pvData,DWORD cbData,UINT * piSlot)300 STDMETHODIMP CMruBase::AddData(LPCVOID pvData, DWORD cbData, UINT *piSlot)
301 {
302 UINT iSlot;
303 HRESULT hr = FindData(pvData, cbData, &iSlot);
304 if (FAILED(hr))
305 {
306 iSlot = _UpdateSlots(m_cSlots);
307 hr = _AddItem(iSlot, pvData, cbData);
308 if (FAILED(hr))
309 return hr;
310 }
311 else
312 {
313 iSlot = _UpdateSlots(iSlot);
314 hr = S_OK;
315 }
316
317 if (piSlot)
318 *piSlot = iSlot;
319
320 return hr;
321 }
322
FindData(LPCVOID pvData,DWORD cbData,UINT * piSlot)323 STDMETHODIMP CMruBase::FindData(LPCVOID pvData, DWORD cbData, UINT *piSlot)
324 {
325 if (m_cSlots <= 0)
326 return E_FAIL;
327
328 UINT iSlot = 0;
329 SLOTITEMDATA *pItem;
330 while (FAILED(_GetItem(iSlot, &pItem)) || !_IsEqual(pItem, pvData, cbData))
331 {
332 if (++iSlot >= m_cSlots)
333 return E_FAIL;
334 }
335
336 *piSlot = iSlot;
337 return S_OK;
338 }
339
GetData(UINT iSlot,LPVOID pvData,DWORD cbData)340 STDMETHODIMP CMruBase::GetData(UINT iSlot, LPVOID pvData, DWORD cbData)
341 {
342 SLOTITEMDATA *pItem;
343 HRESULT hr = _GetItem(iSlot, &pItem);
344 if (FAILED(hr))
345 return hr;
346
347 if (cbData < pItem->cbData)
348 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
349
350 CopyMemory(pvData, pItem->pvData, pItem->cbData);
351 return hr;
352 }
353
QueryInfo(UINT iSlot,UINT * piGotSlot,DWORD * pcbData)354 STDMETHODIMP CMruBase::QueryInfo(UINT iSlot, UINT *piGotSlot, DWORD *pcbData)
355 {
356 UINT iGotSlot;
357 HRESULT hr = _GetSlot(iSlot, &iGotSlot);
358 if (FAILED(hr))
359 return hr;
360
361 if (piGotSlot)
362 *piGotSlot = iGotSlot;
363
364 if (pcbData)
365 {
366 SLOTITEMDATA *pItem;
367 hr = _GetSlotItem(iGotSlot, &pItem);
368 if (SUCCEEDED(hr))
369 *pcbData = pItem->cbData;
370 }
371
372 return hr;
373 }
374
Delete(UINT iSlot)375 STDMETHODIMP CMruBase::Delete(UINT iSlot)
376 {
377 UINT uSlot;
378 HRESULT hr = _RemoveSlot(iSlot, &uSlot);
379 if (FAILED(hr))
380 return hr;
381
382 _DeleteItem(uSlot);
383 return hr;
384 }
385
_IsEqual(const SLOTITEMDATA * pItem,LPCVOID pvData,UINT cbData) const386 BOOL CMruBase::_IsEqual(const SLOTITEMDATA *pItem, LPCVOID pvData, UINT cbData) const
387 {
388 if (m_fnCompare)
389 return m_fnCompare(pvData, pItem->pvData, cbData) == 0;
390
391 switch (m_dwFlags & COMPARE_BY_MASK)
392 {
393 case COMPARE_BY_MEMCMP:
394 if (pItem->cbData != cbData)
395 return FALSE;
396 return memcmp(pvData, pItem->pvData, cbData) == 0;
397
398 case COMPARE_BY_STRCMPIW:
399 return StrCmpIW((LPCWSTR)pvData, (LPCWSTR)pItem->pvData) == 0;
400
401 case COMPARE_BY_STRCMPW:
402 return StrCmpW((LPCWSTR)pvData, (LPCWSTR)pItem->pvData) == 0;
403
404 case COMPARE_BY_IEILISEQUAL:
405 return IEILIsEqual((LPCITEMIDLIST)pvData, (LPCITEMIDLIST)pItem->pvData, FALSE);
406
407 default:
408 ERR("0x%08X\n", m_dwFlags);
409 return FALSE;
410 }
411 }
412
_DeleteValue(LPCWSTR pszValue)413 DWORD CMruBase::_DeleteValue(LPCWSTR pszValue)
414 {
415 return SHDeleteValueW(m_hKey, NULL, pszValue);
416 }
417
_UseEmptySlot(UINT * piSlot)418 HRESULT CMruBase::_UseEmptySlot(UINT *piSlot)
419 {
420 if (!m_bChecked)
421 _CheckUsedSlots();
422
423 if (!m_cSlotRooms)
424 return E_FAIL;
425
426 UINT iSlot = 0;
427 for (SLOTITEMDATA *pItem = m_pSlots; (pItem->dwFlags & SLOT_SET); ++pItem)
428 {
429 if (++iSlot >= m_cSlotRooms)
430 return E_FAIL;
431 }
432
433 m_pSlots[iSlot].dwFlags |= SLOT_SET;
434 *piSlot = iSlot;
435 ++m_cSlots;
436
437 return S_OK;
438 }
439
440 class CMruShortList
441 : public CMruBase
442 {
443 protected:
444 LPWSTR m_pszSlotData = NULL;
445
446 HRESULT _InitSlots() override;
447 void _SaveSlots() override;
448 UINT _UpdateSlots(UINT iSlot) override;
449 void _SlotString(UINT iSlot, LPWSTR psz, DWORD cch) override;
450 HRESULT _GetSlot(UINT iSlot, UINT *puSlot) override;
451 HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) override;
452 friend class CMruLongList;
453
454 public:
CMruShortList()455 CMruShortList()
456 {
457 }
458
~CMruShortList()459 ~CMruShortList() override
460 {
461 m_pszSlotData = (LPWSTR)::LocalFree(m_pszSlotData);
462 }
463 };
464
_InitSlots()465 HRESULT CMruShortList::_InitSlots()
466 {
467 DWORD cbData = (m_cSlotRooms + 1) * sizeof(WCHAR);
468 m_pszSlotData = (LPWSTR)LocalAlloc(LPTR, cbData);
469 if (!m_pszSlotData)
470 return E_OUTOFMEMORY;
471
472 if (SHGetValueW(m_hKey, NULL, L"MRUList", NULL, m_pszSlotData, &cbData) == ERROR_SUCCESS)
473 m_cSlots = (cbData / sizeof(WCHAR)) - 1;
474
475 m_pszSlotData[m_cSlots] = UNICODE_NULL;
476 return S_OK;
477 }
478
_SaveSlots()479 void CMruShortList::_SaveSlots()
480 {
481 if (m_bNeedSave)
482 {
483 DWORD cbData = (m_cSlots + 1) * sizeof(WCHAR);
484 SHSetValueW(m_hKey, NULL, L"MRUList", REG_SZ, m_pszSlotData, cbData);
485 m_bNeedSave = FALSE;
486 }
487 }
488
489 // NOTE: MRUList uses lowercase alphabet for history of most recently used items.
_UpdateSlots(UINT iSlot)490 UINT CMruShortList::_UpdateSlots(UINT iSlot)
491 {
492 UINT iData, cDataToMove = iSlot;
493
494 if (iSlot == m_cSlots)
495 {
496 if (SUCCEEDED(_UseEmptySlot(&iData)))
497 {
498 ++cDataToMove;
499 }
500 else
501 {
502 // This code is getting the item index from a lowercase letter.
503 iData = m_pszSlotData[m_cSlots - 1] - L'a';
504 --cDataToMove;
505 }
506 }
507 else
508 {
509 iData = m_pszSlotData[iSlot] - L'a';
510 }
511
512 if (cDataToMove)
513 {
514 MoveMemory(m_pszSlotData + 1, m_pszSlotData, cDataToMove * sizeof(WCHAR));
515 m_pszSlotData[0] = (WCHAR)(L'a' + iData);
516 m_bNeedSave = TRUE;
517 }
518
519 return iData;
520 }
521
_SlotString(UINT iSlot,LPWSTR psz,DWORD cch)522 void CMruShortList::_SlotString(UINT iSlot, LPWSTR psz, DWORD cch)
523 {
524 if (cch >= 2)
525 {
526 psz[0] = (WCHAR)(L'a' + iSlot);
527 psz[1] = UNICODE_NULL;
528 }
529 }
530
_GetSlot(UINT iSlot,UINT * puSlot)531 HRESULT CMruShortList::_GetSlot(UINT iSlot, UINT *puSlot)
532 {
533 if (iSlot >= m_cSlots)
534 return E_FAIL;
535
536 UINT iData = m_pszSlotData[iSlot] - L'a';
537 if (iData >= m_cSlotRooms)
538 return E_FAIL;
539
540 *puSlot = iData;
541 m_pSlots[iData].dwFlags |= SLOT_SET;
542 return S_OK;
543 }
544
_RemoveSlot(UINT iSlot,UINT * puSlot)545 HRESULT CMruShortList::_RemoveSlot(UINT iSlot, UINT *puSlot)
546 {
547 HRESULT hr = _GetSlot(iSlot, puSlot);
548 if (FAILED(hr))
549 return hr;
550
551 MoveMemory(&m_pszSlotData[iSlot], &m_pszSlotData[iSlot + 1], (m_cSlots - iSlot) * sizeof(WCHAR));
552 --m_cSlots;
553 m_pSlots->dwFlags &= ~SLOT_SET;
554 m_bNeedSave = TRUE;
555
556 return hr;
557 }
558
559 class CMruLongList
560 : public CMruBase
561 {
562 protected:
563 UINT *m_puSlotData = NULL; // The slot data
564
565 void _ImportShortList();
566
567 HRESULT _InitSlots() override;
568 void _SaveSlots() override;
569 UINT _UpdateSlots(UINT iSlot) override;
570 void _SlotString(UINT iSlot, LPWSTR psz, DWORD cch) override;
571 HRESULT _GetSlot(UINT iSlot, UINT *puSlot) override;
572 HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) override;
573
574 public:
CMruLongList()575 CMruLongList()
576 {
577 }
578
~CMruLongList()579 ~CMruLongList() override
580 {
581 m_puSlotData = (UINT*)::LocalFree(m_puSlotData);
582 }
583 };
584
_InitSlots()585 HRESULT CMruLongList::_InitSlots()
586 {
587 DWORD cbData = (m_cSlotRooms + 1) * sizeof(UINT);
588 m_puSlotData = (UINT*)LocalAlloc(LPTR, cbData);
589 if (!m_puSlotData)
590 return E_OUTOFMEMORY;
591
592 if (SHGetValueW(m_hKey, NULL, L"MRUListEx", NULL, m_puSlotData, &cbData) == ERROR_SUCCESS)
593 m_cSlots = (cbData / sizeof(UINT)) - 1;
594 else
595 _ImportShortList();
596
597 m_puSlotData[m_cSlots] = MAXDWORD;
598 return S_OK;
599 }
600
_SaveSlots()601 void CMruLongList::_SaveSlots()
602 {
603 if (m_bNeedSave)
604 {
605 SHSetValueW(m_hKey, NULL, L"MRUListEx", REG_BINARY, m_puSlotData,
606 (m_cSlots + 1) * sizeof(UINT));
607 m_bNeedSave = FALSE;
608 }
609 }
610
_UpdateSlots(UINT iSlot)611 UINT CMruLongList::_UpdateSlots(UINT iSlot)
612 {
613 UINT cSlotsToMove, uSlotData;
614
615 cSlotsToMove = iSlot;
616 if (iSlot == m_cSlots)
617 {
618 if (SUCCEEDED(_UseEmptySlot(&uSlotData)))
619 {
620 ++cSlotsToMove;
621 }
622 else
623 {
624 uSlotData = m_puSlotData[m_cSlots - 1];
625 --cSlotsToMove;
626 }
627 }
628 else
629 {
630 uSlotData = m_puSlotData[iSlot];
631 }
632
633 if (cSlotsToMove > 0)
634 {
635 MoveMemory(m_puSlotData + 1, m_puSlotData, cSlotsToMove * sizeof(UINT));
636 m_puSlotData[0] = uSlotData;
637 m_bNeedSave = TRUE;
638 }
639
640 return uSlotData;
641 }
642
_SlotString(UINT iSlot,LPWSTR psz,DWORD cch)643 void CMruLongList::_SlotString(UINT iSlot, LPWSTR psz, DWORD cch)
644 {
645 StringCchPrintfW(psz, cch, L"%d", iSlot);
646 }
647
_GetSlot(UINT iSlot,UINT * puSlot)648 HRESULT CMruLongList::_GetSlot(UINT iSlot, UINT *puSlot)
649 {
650 if (iSlot >= m_cSlots)
651 return E_FAIL;
652
653 UINT uSlotData = m_puSlotData[iSlot];
654 if (uSlotData >= m_cSlotRooms)
655 return E_FAIL;
656
657 *puSlot = uSlotData;
658 m_pSlots[uSlotData].dwFlags |= SLOT_SET;
659 return S_OK;
660 }
661
_RemoveSlot(UINT iSlot,UINT * puSlot)662 HRESULT CMruLongList::_RemoveSlot(UINT iSlot, UINT *puSlot)
663 {
664 HRESULT hr = _GetSlot(iSlot, puSlot);
665 if (FAILED(hr))
666 return hr;
667
668 MoveMemory(&m_puSlotData[iSlot], &m_puSlotData[iSlot + 1], (m_cSlots - iSlot) * sizeof(UINT));
669 --m_cSlots;
670 m_pSlots[0].dwFlags &= ~SLOT_SET;
671 m_bNeedSave = TRUE;
672
673 return hr;
674 }
675
_ImportShortList()676 void CMruLongList::_ImportShortList()
677 {
678 CMruShortList *pShortList = new CMruShortList();
679 if (!pShortList)
680 return;
681
682 HRESULT hr = pShortList->InitData(m_cSlotRooms, 0, m_hKey, NULL, NULL);
683 if (SUCCEEDED(hr))
684 {
685 for (;;)
686 {
687 UINT iSlot;
688 hr = pShortList->_GetSlot(m_cSlots, &iSlot);
689 if (FAILED(hr))
690 break;
691
692 SLOTITEMDATA *pItem;
693 hr = pShortList->_GetSlotItem(iSlot, &pItem);
694 if (FAILED(hr))
695 break;
696
697 _AddItem(iSlot, pItem->pvData, pItem->cbData);
698 pShortList->_DeleteItem(iSlot);
699
700 m_puSlotData[m_cSlots++] = iSlot;
701 }
702
703 m_bNeedSave = TRUE;
704 }
705
706 SHDeleteValueW(m_hKey, NULL, L"MRUList");
707 pShortList->Release();
708 }
709
710 EXTERN_C HRESULT
CMruLongList_CreateInstance(DWORD_PTR dwUnused1,void ** ppv,DWORD_PTR dwUnused3)711 CMruLongList_CreateInstance(DWORD_PTR dwUnused1, void **ppv, DWORD_PTR dwUnused3)
712 {
713 UNREFERENCED_PARAMETER(dwUnused1);
714 UNREFERENCED_PARAMETER(dwUnused3);
715
716 TRACE("%p %p %p\n", dwUnused1, ppv, dwUnused3);
717
718 if (!ppv)
719 return E_POINTER;
720
721 CMruLongList *pMruList = new CMruLongList();
722 *ppv = static_cast<IMruDataList*>(pMruList);
723 TRACE("%p\n", *ppv);
724
725 return S_OK;
726 }
727
728 class CMruNode
729 : public CMruLongList
730 {
731 protected:
732 UINT m_iSlot = 0; // The slot index
733 CMruNode *m_pParent = NULL; // The parent
734 IShellFolder *m_pShellFolder = NULL; // The shell folder
735
736 BOOL _InitLate();
737 BOOL _IsEqual(SLOTITEMDATA *pItem, LPCVOID pvData, UINT cbData);
738 DWORD _DeleteValue(LPCWSTR pszValue) override;
739
740 HRESULT _CreateNode(UINT iSlot, CMruNode **ppNewNode);
741 HRESULT _AddPidl(UINT iSlot, LPCITEMIDLIST pidl);
742 HRESULT _FindPidl(LPCITEMIDLIST pidl, UINT *piSlot);
743 HRESULT _GetPidlSlot(LPCITEMIDLIST pidl, BOOL bAdd, UINT *piSlot);
744
745 public:
CMruNode()746 CMruNode() { }
747 CMruNode(CMruNode *pParent, UINT iSlot);
748 ~CMruNode() override;
749
750 CMruNode *GetParent();
751
752 HRESULT BindToSlot(UINT iSlot, IShellFolder **ppSF);
753 HRESULT GetNode(BOOL bAdd, LPCITEMIDLIST pidl, CMruNode **pNewNode);
754 HRESULT GetNodeSlot(UINT *pnNodeSlot);
755 HRESULT SetNodeSlot(UINT nNodeSlot);
756
757 HRESULT RemoveLeast(UINT *pnNodeSlot);
758 HRESULT Clear(CMruPidlList *pList);
759 };
760
CMruNode(CMruNode * pParent,UINT iSlot)761 CMruNode::CMruNode(CMruNode *pParent, UINT iSlot)
762 {
763 m_iSlot = iSlot;
764 m_pParent = pParent;
765 pParent->AddRef();
766 }
767
~CMruNode()768 CMruNode::~CMruNode()
769 {
770 if (m_pParent)
771 {
772 m_pParent->Release();
773 m_pParent = NULL;
774 }
775
776 if (m_pShellFolder)
777 {
778 m_pShellFolder->Release();
779 m_pShellFolder = NULL;
780 }
781 }
782
GetParent()783 CMruNode *CMruNode::GetParent()
784 {
785 if (m_pParent)
786 m_pParent->AddRef();
787 return m_pParent;
788 }
789
_CreateNode(UINT iSlot,CMruNode ** ppNewNode)790 HRESULT CMruNode::_CreateNode(UINT iSlot, CMruNode **ppNewNode)
791 {
792 CMruNode *pNewNode = new CMruNode(this, iSlot);
793 if (!pNewNode)
794 return E_OUTOFMEMORY;
795
796 WCHAR szSubKey[12];
797 _SlotString(iSlot, szSubKey, _countof(szSubKey));
798
799 HRESULT hr = pNewNode->InitData(m_cSlotRooms, 0, m_hKey, szSubKey, NULL);
800 if (FAILED(hr))
801 pNewNode->Release();
802 else
803 *ppNewNode = pNewNode;
804
805 return hr;
806 }
807
GetNode(BOOL bAdd,LPCITEMIDLIST pidl,CMruNode ** ppNewNode)808 HRESULT CMruNode::GetNode(BOOL bAdd, LPCITEMIDLIST pidl, CMruNode **ppNewNode)
809 {
810 if (!pidl || !pidl->mkid.cb)
811 {
812 *ppNewNode = this;
813 AddRef();
814 return S_OK;
815 }
816
817 if (!_InitLate())
818 return E_FAIL;
819
820 UINT iSlot;
821 HRESULT hr = _GetPidlSlot(pidl, bAdd, &iSlot);
822 if (FAILED(hr))
823 {
824 if (!bAdd)
825 {
826 *ppNewNode = this;
827 AddRef();
828 return S_FALSE;
829 }
830 return hr;
831 }
832
833 CMruNode *pNewNode;
834 hr = _CreateNode(iSlot, &pNewNode);
835 if (SUCCEEDED(hr))
836 {
837 _SaveSlots();
838
839 LPCITEMIDLIST pidl2 = (LPCITEMIDLIST)((LPBYTE)pidl + pidl->mkid.cb);
840 pNewNode->GetNode(bAdd, pidl2, ppNewNode);
841 pNewNode->Release();
842 }
843
844 return hr;
845 }
846
BindToSlot(UINT iSlot,IShellFolder ** ppSF)847 HRESULT CMruNode::BindToSlot(UINT iSlot, IShellFolder **ppSF)
848 {
849 SLOTITEMDATA *pItem;
850 HRESULT hr = _GetSlotItem(iSlot, &pItem);
851 if (FAILED(hr))
852 return hr;
853
854 return m_pShellFolder->BindToObject((LPITEMIDLIST)pItem->pvData,
855 NULL,
856 IID_IShellFolder,
857 (void **)ppSF);
858 }
859
_InitLate()860 BOOL CMruNode::_InitLate()
861 {
862 if (!m_pShellFolder)
863 {
864 if (m_pParent)
865 m_pParent->BindToSlot(m_iSlot, &m_pShellFolder);
866 else
867 SHGetDesktopFolder(&m_pShellFolder);
868 }
869 return !!m_pShellFolder;
870 }
871
_IsEqual(SLOTITEMDATA * pItem,LPCVOID pvData,UINT cbData)872 BOOL CMruNode::_IsEqual(SLOTITEMDATA *pItem, LPCVOID pvData, UINT cbData)
873 {
874 return m_pShellFolder->CompareIDs(0x10000000,
875 (LPITEMIDLIST)pItem->pvData,
876 (LPCITEMIDLIST)pvData) == 0;
877 }
878
GetNodeSlot(UINT * pnNodeSlot)879 HRESULT CMruNode::GetNodeSlot(UINT *pnNodeSlot)
880 {
881 DWORD dwData, cbData = sizeof(dwData);
882 DWORD error = SHGetValueW(m_hKey, NULL, L"NodeSlot", NULL, &dwData, (pnNodeSlot ? &cbData : NULL));
883 if (error != ERROR_SUCCESS)
884 return E_FAIL;
885 *pnNodeSlot = (UINT)dwData;
886 return S_OK;
887 }
888
SetNodeSlot(UINT nNodeSlot)889 HRESULT CMruNode::SetNodeSlot(UINT nNodeSlot)
890 {
891 DWORD dwData = nNodeSlot;
892 if (SHSetValueW(m_hKey, NULL, L"NodeSlot", REG_DWORD, &dwData, sizeof(dwData)) != ERROR_SUCCESS)
893 return E_FAIL;
894 return S_OK;
895 }
896
_AddPidl(UINT iSlot,LPCITEMIDLIST pidl)897 HRESULT CMruNode::_AddPidl(UINT iSlot, LPCITEMIDLIST pidl)
898 {
899 return CMruBase::_AddItem(iSlot, pidl, sizeof(WORD) + pidl->mkid.cb);
900 }
901
_DeleteValue(LPCWSTR pszValue)902 DWORD CMruNode::_DeleteValue(LPCWSTR pszValue)
903 {
904 CMruBase::_DeleteValue(pszValue);
905 return SHDeleteKeyW(m_hKey, pszValue);
906 }
907
_FindPidl(LPCITEMIDLIST pidl,UINT * piSlot)908 HRESULT CMruNode::_FindPidl(LPCITEMIDLIST pidl, UINT *piSlot)
909 {
910 return FindData(pidl, sizeof(WORD) + pidl->mkid.cb, piSlot);
911 }
912
_GetPidlSlot(LPCITEMIDLIST pidl,BOOL bAdd,UINT * piSlot)913 HRESULT CMruNode::_GetPidlSlot(LPCITEMIDLIST pidl, BOOL bAdd, UINT *piSlot)
914 {
915 LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
916 if (!pidlFirst)
917 return E_OUTOFMEMORY;
918
919 UINT iSlot;
920 HRESULT hr = _FindPidl(pidlFirst, &iSlot);
921 if (SUCCEEDED(hr))
922 {
923 *piSlot = _UpdateSlots(iSlot);
924 hr = S_OK;
925 }
926 else if (bAdd)
927 {
928 *piSlot = _UpdateSlots(m_cSlots);
929 hr = _AddPidl(*piSlot, pidlFirst);
930 }
931
932 ILFree(pidlFirst);
933 return hr;
934 }
935
RemoveLeast(UINT * pnNodeSlot)936 HRESULT CMruNode::RemoveLeast(UINT *pnNodeSlot)
937 {
938 if (!m_cSlots)
939 {
940 GetNodeSlot(pnNodeSlot);
941 return S_FALSE;
942 }
943
944 UINT uSlot;
945 HRESULT hr = _GetSlot(m_cSlots - 1, &uSlot);
946 if (FAILED(hr))
947 return hr;
948
949 CMruNode *pNode;
950 hr = _CreateNode(uSlot, &pNode);
951 if (SUCCEEDED(hr))
952 {
953 hr = pNode->RemoveLeast(pnNodeSlot);
954 pNode->Release();
955 }
956
957 if (hr == S_FALSE)
958 {
959 Delete(m_cSlots - 1);
960 if (m_cSlots || SUCCEEDED(GetNodeSlot(0)))
961 return S_OK;
962 }
963
964 return hr;
965 }
966
967 class CMruPidlList
968 : public CMruNode
969 , public IMruPidlList
970 {
971 protected:
972 LPBYTE m_pbNodeSlots = NULL; // The node slots (contains SLOT_... flags)
973 DWORD m_cMaxNodeSlots = 0; // The upper bound of the node slot index
974 HANDLE m_hMutex = NULL; // The mutex (for sync)
975
976 BOOL _LoadNodeSlots();
977 void _SaveNodeSlots();
978 HRESULT _InitNodeSlots();
979
980 public:
CMruPidlList()981 CMruPidlList() { }
982 ~CMruPidlList() override;
983
984 HRESULT GetEmptySlot(UINT *pnNodeSlot);
985 void EmptyNodeSlot(UINT nNodeSlot);
986
987 // IUnknown methods
988 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override;
AddRef()989 STDMETHODIMP_(ULONG) AddRef() override
990 {
991 return CMruBase::AddRef();
992 }
Release()993 STDMETHODIMP_(ULONG) Release() override
994 {
995 return CMruBase::Release();
996 }
997
998 // IMruPidlList methods
999 STDMETHODIMP InitList(UINT cMRUSize, HKEY hKey, LPCWSTR pszSubKey) override;
1000 STDMETHODIMP UsePidl(LPCITEMIDLIST pidl, UINT *pnNodeSlot) override;
1001 STDMETHODIMP QueryPidl(
1002 LPCITEMIDLIST pidl,
1003 UINT cSlots,
1004 UINT *pnNodeSlots,
1005 UINT *pcNodeSlots) override;
1006 STDMETHODIMP PruneKids(LPCITEMIDLIST pidl) override;
1007 };
1008
~CMruPidlList()1009 CMruPidlList::~CMruPidlList()
1010 {
1011 m_pbNodeSlots = (LPBYTE)::LocalFree(m_pbNodeSlots);
1012 if (m_hMutex)
1013 {
1014 ::CloseHandle(m_hMutex);
1015 m_hMutex = NULL;
1016 }
1017 }
1018
QueryInterface(REFIID riid,void ** ppvObj)1019 STDMETHODIMP CMruPidlList::QueryInterface(REFIID riid, void **ppvObj)
1020 {
1021 if (!ppvObj)
1022 return E_POINTER;
1023
1024 if (::IsEqualGUID(riid, IID_IMruPidlList) || ::IsEqualGUID(riid, IID_IUnknown))
1025 {
1026 *ppvObj = static_cast<IMruPidlList*>(this);
1027 AddRef();
1028 return S_OK;
1029 }
1030
1031 ERR("%s: E_NOINTERFACE\n", debugstr_guid(&riid));
1032 return E_NOINTERFACE;
1033 }
1034
_LoadNodeSlots()1035 BOOL CMruPidlList::_LoadNodeSlots()
1036 {
1037 DWORD cbNodeSlots = m_cSlotRooms * sizeof(BYTE);
1038 if (SHGetValueW(m_hKey, NULL, L"NodeSlots", NULL, m_pbNodeSlots, &cbNodeSlots) != ERROR_SUCCESS)
1039 return FALSE;
1040 m_cMaxNodeSlots = cbNodeSlots / sizeof(BYTE);
1041 return TRUE;
1042 }
1043
_SaveNodeSlots()1044 void CMruPidlList::_SaveNodeSlots()
1045 {
1046 DWORD cbNodeSlots = m_cMaxNodeSlots * sizeof(BYTE);
1047 SHSetValueW(m_hKey, NULL, L"NodeSlots", REG_BINARY, m_pbNodeSlots, cbNodeSlots);
1048 }
1049
_InitNodeSlots()1050 HRESULT CMruPidlList::_InitNodeSlots()
1051 {
1052 m_pbNodeSlots = (BYTE*)LocalAlloc(LPTR, m_cSlotRooms * sizeof(BYTE));
1053 if (!m_pbNodeSlots)
1054 return E_OUTOFMEMORY;
1055
1056 _LoadNodeSlots();
1057 m_bNeedSave = TRUE;
1058 _SaveNodeSlots();
1059
1060 return S_OK;
1061 }
1062
GetEmptySlot(UINT * pnNodeSlot)1063 HRESULT CMruPidlList::GetEmptySlot(UINT *pnNodeSlot)
1064 {
1065 *pnNodeSlot = 0;
1066
1067 if (!_LoadNodeSlots())
1068 return E_FAIL;
1069
1070 if (m_cMaxNodeSlots < m_cSlotRooms)
1071 {
1072 m_pbNodeSlots[m_cMaxNodeSlots] = SLOT_SET;
1073 *pnNodeSlot = ++m_cMaxNodeSlots;
1074 _SaveNodeSlots();
1075 return S_OK;
1076 }
1077
1078 for (UINT iNodeSlot = 0; iNodeSlot < m_cMaxNodeSlots; ++iNodeSlot)
1079 {
1080 if (m_pbNodeSlots[iNodeSlot] & SLOT_SET)
1081 continue;
1082
1083 m_pbNodeSlots[iNodeSlot] = SLOT_SET;
1084 *pnNodeSlot = iNodeSlot + 1; // nNodeSlot is 1-base
1085 _SaveNodeSlots();
1086 return S_OK;
1087 }
1088
1089 HRESULT hr = E_FAIL;
1090 if (SUCCEEDED(RemoveLeast(pnNodeSlot)) && *pnNodeSlot)
1091 hr = S_OK;
1092
1093 _SaveNodeSlots();
1094 return hr;
1095 }
1096
InitList(UINT cMRUSize,HKEY hKey,LPCWSTR pszSubKey)1097 STDMETHODIMP CMruPidlList::InitList(UINT cMRUSize, HKEY hKey, LPCWSTR pszSubKey)
1098 {
1099 TRACE("%p -> %u %p %s\n", this, cMRUSize, hKey, debugstr_w(pszSubKey));
1100
1101 HRESULT hr = InitData(cMRUSize, 0, hKey, pszSubKey, NULL);
1102 if (FAILED(hr))
1103 {
1104 ERR("0x%08lX\n", hr);
1105 return hr;
1106 }
1107
1108 hr = _InitNodeSlots();
1109 if (FAILED(hr))
1110 {
1111 ERR("0x%08lX\n", hr);
1112 return hr;
1113 }
1114
1115 m_hMutex = ::CreateMutexW(NULL, FALSE, L"Shell.CMruPidlList");
1116 if (!m_hMutex)
1117 {
1118 hr = HRESULT_FROM_WIN32(GetLastError());
1119 ERR("0x%08lX\n", hr);
1120 }
1121
1122 return hr;
1123 }
1124
UsePidl(LPCITEMIDLIST pidl,UINT * pnNodeSlot)1125 STDMETHODIMP CMruPidlList::UsePidl(LPCITEMIDLIST pidl, UINT *pnNodeSlot)
1126 {
1127 TRACE("%p -> %p %p\n", this, pidl, pnNodeSlot);
1128
1129 CSafeMutex mutex;
1130 HRESULT hr = mutex.Enter(m_hMutex);
1131 if (FAILED(hr))
1132 {
1133 ERR("0x%08lX\n", hr);
1134 return hr;
1135 }
1136
1137 *pnNodeSlot = 0;
1138
1139 CMruNode *pNode;
1140 hr = GetNode(TRUE, pidl, &pNode);
1141 if (FAILED(hr))
1142 {
1143 ERR("0x%08lX\n", hr);
1144 return hr;
1145 }
1146
1147 hr = pNode->GetNodeSlot(pnNodeSlot);
1148 if (FAILED(hr))
1149 {
1150 hr = GetEmptySlot(pnNodeSlot);
1151 if (SUCCEEDED(hr))
1152 {
1153 hr = pNode->SetNodeSlot(*pnNodeSlot);
1154 }
1155 }
1156
1157 pNode->Release();
1158 return hr;
1159 }
1160
QueryPidl(LPCITEMIDLIST pidl,UINT cSlots,UINT * pnNodeSlots,UINT * pcNodeSlots)1161 STDMETHODIMP CMruPidlList::QueryPidl(
1162 LPCITEMIDLIST pidl,
1163 UINT cSlots,
1164 UINT *pnNodeSlots,
1165 UINT *pcNodeSlots)
1166 {
1167 TRACE("%p -> %p %u %p %p\n", this, pidl, cSlots, pnNodeSlots, pcNodeSlots);
1168
1169 CSafeMutex mutex;
1170 HRESULT hr = mutex.Enter(m_hMutex);
1171 if (FAILED(hr))
1172 {
1173 ERR("0x%08lX\n", hr);
1174 return hr;
1175 }
1176
1177 *pcNodeSlots = 0;
1178
1179 CMruNode *pNode;
1180 hr = GetNode(FALSE, pidl, &pNode);
1181 if (FAILED(hr))
1182 {
1183 ERR("0x%08lX\n", hr);
1184 return hr;
1185 }
1186
1187 while (pNode && *pcNodeSlots < cSlots)
1188 {
1189 CMruNode *pParent = pNode->GetParent();
1190 if (SUCCEEDED(pNode->GetNodeSlot(&pnNodeSlots[*pcNodeSlots])))
1191 ++(*pcNodeSlots);
1192 else if (hr == S_OK && !*pcNodeSlots)
1193 hr = S_FALSE;
1194
1195 pNode->Release();
1196 pNode = pParent;
1197 }
1198
1199 if (pNode)
1200 pNode->Release();
1201
1202 if (SUCCEEDED(hr) && !*pcNodeSlots)
1203 hr = E_FAIL;
1204
1205 return hr;
1206 }
1207
PruneKids(LPCITEMIDLIST pidl)1208 STDMETHODIMP CMruPidlList::PruneKids(LPCITEMIDLIST pidl)
1209 {
1210 TRACE("%p -> %p\n", this, pidl);
1211
1212 CSafeMutex mutex;
1213 HRESULT hr = mutex.Enter(m_hMutex);
1214 if (FAILED(hr))
1215 {
1216 ERR("0x%08lX\n", hr);
1217 return hr;
1218 }
1219
1220 if (!_LoadNodeSlots())
1221 return hr;
1222
1223 CMruNode *pNode;
1224 hr = GetNode(FALSE, pidl, &pNode);
1225 if (FAILED(hr))
1226 return hr;
1227
1228 if (hr == S_OK)
1229 hr = pNode->Clear(this);
1230 else
1231 hr = E_FAIL;
1232
1233 pNode->Release();
1234
1235 _SaveNodeSlots();
1236 return hr;
1237 }
1238
EmptyNodeSlot(UINT nNodeSlot)1239 void CMruPidlList::EmptyNodeSlot(UINT nNodeSlot)
1240 {
1241 m_pbNodeSlots[nNodeSlot - 1] = 0; // nNodeSlot is 1-base
1242 m_bNeedSave = TRUE;
1243 }
1244
CMruPidlList_CreateInstance(DWORD_PTR dwUnused1,void ** ppv,DWORD_PTR dwUnused3)1245 EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD_PTR dwUnused1, void **ppv, DWORD_PTR dwUnused3)
1246 {
1247 UNREFERENCED_PARAMETER(dwUnused1);
1248 UNREFERENCED_PARAMETER(dwUnused3);
1249
1250 TRACE("%p %p %p\n", dwUnused1, ppv, dwUnused3);
1251
1252 if (!ppv)
1253 return E_POINTER;
1254
1255 *ppv = NULL;
1256
1257 CMruPidlList *pMruList = new CMruPidlList();
1258 if (pMruList == NULL)
1259 return E_OUTOFMEMORY;
1260
1261 *ppv = static_cast<IMruPidlList*>(pMruList);
1262 TRACE("%p\n", *ppv);
1263 return S_OK;
1264 }
1265
Clear(CMruPidlList * pList)1266 HRESULT CMruNode::Clear(CMruPidlList *pList)
1267 {
1268 UINT uSlot, nNodeSlot;
1269 HRESULT hr;
1270
1271 while (SUCCEEDED(_GetSlot(0, &uSlot)))
1272 {
1273 CMruNode *pNode;
1274 hr = _CreateNode(uSlot, &pNode);
1275 if (SUCCEEDED(hr))
1276 {
1277 hr = pNode->GetNodeSlot(&nNodeSlot);
1278 if (SUCCEEDED(hr))
1279 pList->EmptyNodeSlot(nNodeSlot);
1280
1281 pNode->Clear(pList);
1282 pNode->Release();
1283 }
1284 Delete(0);
1285 }
1286
1287 return S_OK;
1288 }
1289
1290 class CMruClassFactory : public IClassFactory
1291 {
1292 protected:
1293 LONG m_cRefs = 1;
1294
1295 public:
CMruClassFactory()1296 CMruClassFactory()
1297 {
1298 SHDOCVW_LockModule();
1299 }
~CMruClassFactory()1300 virtual ~CMruClassFactory()
1301 {
1302 SHDOCVW_UnlockModule();
1303 }
1304
1305 // IUnknown methods
1306 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override;
AddRef()1307 STDMETHODIMP_(ULONG) AddRef() override
1308 {
1309 return ::InterlockedIncrement(&m_cRefs);
1310 }
Release()1311 STDMETHODIMP_(ULONG) Release()
1312 {
1313 if (::InterlockedDecrement(&m_cRefs) == 0)
1314 {
1315 delete this;
1316 return 0;
1317 }
1318 return m_cRefs;
1319 }
1320
1321 // IClassFactory methods
1322 STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
1323 STDMETHODIMP LockServer(BOOL fLock);
1324
operator new(size_t size)1325 static void* operator new(size_t size)
1326 {
1327 return ::LocalAlloc(LPTR, size);
1328 }
operator delete(void * ptr)1329 static void operator delete(void *ptr)
1330 {
1331 ::LocalFree(ptr);
1332 }
1333 };
1334
QueryInterface(REFIID riid,void ** ppvObj)1335 STDMETHODIMP CMruClassFactory::QueryInterface(REFIID riid, void **ppvObj)
1336 {
1337 if (!ppvObj)
1338 return E_POINTER;
1339 if (IsEqualGUID(riid, IID_IClassFactory) || IsEqualGUID(riid, IID_IUnknown))
1340 {
1341 *ppvObj = static_cast<IClassFactory*>(this);
1342 AddRef();
1343 return S_OK;
1344 }
1345 ERR("%s: E_NOINTERFACE\n", debugstr_guid(&riid));
1346 return E_NOINTERFACE;
1347 }
1348
CreateInstance(IUnknown * pUnkOuter,REFIID riid,void ** ppvObject)1349 STDMETHODIMP CMruClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
1350 {
1351 if (pUnkOuter)
1352 return CLASS_E_NOAGGREGATION;
1353
1354 if (IsEqualGUID(riid, IID_IMruDataList))
1355 return CMruLongList_CreateInstance(0, ppvObject, 0);
1356
1357 if (IsEqualGUID(riid, IID_IMruPidlList))
1358 return CMruPidlList_CreateInstance(0, ppvObject, 0);
1359
1360 return E_NOINTERFACE;
1361 }
1362
LockServer(BOOL fLock)1363 STDMETHODIMP CMruClassFactory::LockServer(BOOL fLock)
1364 {
1365 if (fLock)
1366 SHDOCVW_LockModule();
1367 else
1368 SHDOCVW_UnlockModule();
1369 return S_OK;
1370 }
1371
CMruClassFactory_CreateInstance(REFIID riid,void ** ppv)1372 EXTERN_C HRESULT CMruClassFactory_CreateInstance(REFIID riid, void **ppv)
1373 {
1374 CMruClassFactory *pFactory = new CMruClassFactory();
1375 if (!pFactory)
1376 return E_OUTOFMEMORY;
1377
1378 HRESULT hr = pFactory->QueryInterface(riid, ppv);
1379 pFactory->Release();
1380 return hr;
1381 }
1382