Reactos
1/*
2 * PROJECT: shell32
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Utility functions
5 * COPYRIGHT: ReactOS Team
6 */
7
8#pragma once
9
10#ifndef OPTIONAL_
11 #ifdef __cplusplus
12 #define OPTIONAL_(arg) = arg
13 #else
14 #define OPTIONAL_(arg)
15 #endif
16#endif
17
18#ifdef __cplusplus
19static inline LPWSTR
20SHStrDupW(LPCWSTR Src)
21{
22 LPWSTR Dup;
23 return SUCCEEDED(SHStrDupW(Src, &Dup)) ? Dup : NULL;
24}
25
26static inline UINT
27SHELL_ErrorBox(CMINVOKECOMMANDINFO &cmi, UINT Error)
28{
29 if (cmi.fMask & CMIC_MASK_FLAG_NO_UI)
30 return Error ? Error : ERROR_INTERNAL_ERROR;
31 return SHELL_ErrorBox(cmi.hwnd, Error);
32}
33#endif
34
35static inline BOOL
36IsEqualPersistClassID(IPersist *pPersist, REFCLSID clsid)
37{
38 CLSID temp;
39 return pPersist && SUCCEEDED(pPersist->GetClassID(&temp)) && IsEqualCLSID(clsid, temp);
40}
41
42static inline BOOL
43RegValueExists(HKEY hKey, LPCWSTR Name)
44{
45 return RegQueryValueExW(hKey, Name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
46}
47
48inline BOOL
49RegKeyExists(HKEY hKey, LPCWSTR Path)
50{
51 BOOL ret = !RegOpenKeyExW(hKey, Path, 0, MAXIMUM_ALLOWED, &hKey);
52 if (ret)
53 RegCloseKey(hKey);
54 return ret;
55}
56
57inline UINT
58RegQueryDword(HKEY hKey, PCWSTR pszPath, PCWSTR pszName, DWORD *pnVal)
59{
60 DWORD cb = sizeof(*pnVal);
61 return RegGetValueW(hKey, pszPath, pszName, RRF_RT_REG_DWORD, NULL, pnVal, &cb);
62}
63
64inline DWORD
65RegGetDword(HKEY hKey, PCWSTR pszPath, PCWSTR pszName, DWORD nDefVal)
66{
67 DWORD nVal;
68 return RegQueryDword(hKey, pszPath, pszName, &nVal) == ERROR_SUCCESS ? nVal : nDefVal;
69}
70
71inline DWORD
72RegSetOrDelete(HKEY hKey, LPCWSTR Name, DWORD Type, LPCVOID Data, DWORD Size)
73{
74 if (Data)
75 return RegSetValueExW(hKey, Name, 0, Type, (LPBYTE)Data, Size);
76 else
77 return RegDeleteValueW(hKey, Name);
78}
79
80static inline DWORD
81RegSetString(HKEY hKey, LPCWSTR Name, LPCWSTR Str, DWORD Type OPTIONAL_(REG_SZ))
82{
83 return RegSetValueExW(hKey, Name, 0, Type, (LPBYTE)Str, (lstrlenW(Str) + 1) * sizeof(WCHAR));
84}
85
86typedef struct
87{
88 LPCSTR Verb;
89 WORD CmdId;
90} CMVERBMAP;
91
92HRESULT
93SHELL_MapContextMenuVerbToCmdId(LPCMINVOKECOMMANDINFO pICI, const CMVERBMAP *pMap);
94HRESULT
95SHELL_GetCommandStringImpl(SIZE_T CmdId, UINT uFlags, LPSTR Buf, UINT cchBuf, const CMVERBMAP *pMap);
96
97// SHExtractIconsW is a forward, use this function instead inside shell32
98inline HICON
99SHELL32_SHExtractIcon(LPCWSTR File, int Index, int cx, int cy)
100{
101 HICON hIco;
102 int r = PrivateExtractIconsW(File, Index, cx, cy, &hIco, NULL, 1, 0);
103 return r > 0 ? hIco : NULL;
104}
105
106HRESULT
107SHELL_CreateShell32DefaultExtractIcon(int IconIndex, REFIID riid, LPVOID *ppvOut);
108
109static inline HRESULT
110SHELL_CreateFallbackExtractIconForFolder(REFIID riid, LPVOID *ppvOut)
111{
112 const int id = IDI_SHELL_FOLDER;
113 return SHELL_CreateShell32DefaultExtractIcon(id > 1 ? -id : 0, riid, ppvOut);
114}
115
116static inline HRESULT
117SHELL_CreateFallbackExtractIconForNoAssocFile(REFIID riid, LPVOID *ppvOut)
118{
119 const int id = IDI_SHELL_DOCUMENT;
120 return SHELL_CreateShell32DefaultExtractIcon(id > 1 ? -id : 0, riid, ppvOut);
121}
122
123typedef HDSA HDCIA; // DynamicClassIdArray
124#define DCIA_Create() ( (HDCIA)DSA_Create(sizeof(CLSID), 4) )
125#define DCIA_Destroy(hDCIA) DSA_Destroy((HDSA)(hDCIA))
126#define DCIA_GetCount(hDCIA) DSA_GetItemCount((HDSA)(hDCIA))
127#define DCIA_GetEntry(hDCIA, iItem) ( (const CLSID*)DSA_GetItemPtr((HDSA)(hDCIA), (iItem)) )
128int DCIA_AddEntry(HDCIA hDCIA, REFCLSID rClsId);
129void DCIA_AddShellExSubkey(HDCIA hDCIA, HKEY hProgId, PCWSTR pszSubkey);
130
131#ifdef __cplusplus
132struct ClipboardViewerChain
133{
134 HWND m_hWndNext = HWND_BOTTOM;
135
136 void Unhook(HWND hWnd)
137 {
138 if (m_hWndNext != HWND_BOTTOM)
139 ChangeClipboardChain(hWnd, m_hWndNext);
140 m_hWndNext = HWND_BOTTOM;
141 }
142
143 void Hook(HWND hWnd)
144 {
145 if (m_hWndNext == HWND_BOTTOM)
146 m_hWndNext = SetClipboardViewer(hWnd);
147 }
148
149 LRESULT HandleChangeCBChain(WPARAM wParam, LPARAM lParam)
150 {
151 if (m_hWndNext == (HWND)wParam)
152 return (LRESULT)(m_hWndNext = (HWND)lParam);
153 else if (m_hWndNext && m_hWndNext != HWND_BOTTOM)
154 return ::SendMessageW(m_hWndNext, WM_CHANGECBCHAIN, wParam, lParam);
155 return 0;
156 }
157
158 LRESULT HandleDrawClipboard(WPARAM wParam, LPARAM lParam)
159 {
160 if (m_hWndNext && m_hWndNext != HWND_BOTTOM)
161 return ::SendMessageW(m_hWndNext, WM_DRAWCLIPBOARD, wParam, lParam);
162 return 0;
163 }
164};
165
166struct CCidaChildArrayHelper
167{
168 // Note: This just creates an array pointing to the items and has the same lifetime as the CIDA.
169 // Use _ILCopyCidaToaPidl if you need the items to outlive the CIDA!
170 explicit CCidaChildArrayHelper(const CIDA *pCida)
171 {
172 m_hr = E_OUTOFMEMORY;
173 m_array = (PCUIDLIST_RELATIVE_ARRAY)SHAlloc(pCida->cidl * sizeof(LPITEMIDLIST));
174 if (m_array)
175 {
176 m_hr = S_OK;
177 for (UINT i = 0; i < pCida->cidl; ++i)
178 *(LPITEMIDLIST*)(&m_array[i]) = (LPITEMIDLIST)HIDA_GetPIDLItem(pCida, i);
179 }
180 }
181 ~CCidaChildArrayHelper() { SHFree((LPITEMIDLIST*)m_array); }
182
183 HRESULT hr() const { return m_hr; }
184 PCUIDLIST_RELATIVE_ARRAY GetItems() const { return m_array; }
185
186 HRESULT m_hr;
187 PCUIDLIST_RELATIVE_ARRAY m_array;
188};
189#endif // __cplusplus