1 /*
2 * PROJECT: ReactOS Shell
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: CNetworkConnections Shell Folder items enumerator
5 * COPYRIGHT: Copyright 2008 Johannes Anderwald (johannes.anderwald@reactos.org)
6 */
7
8 #include "precomp.h"
9
ILGetConnData(PCITEMID_CHILD pidl)10 PNETCONIDSTRUCT ILGetConnData(PCITEMID_CHILD pidl)
11 {
12 if (pidl && pidl->mkid.cb >= 2 + sizeof(NETCONIDSTRUCT))
13 {
14 PNETCONIDSTRUCT pData = (PNETCONIDSTRUCT)pidl->mkid.abID;
15 if (pData->Signature == NETCONIDSTRUCT_SIG)
16 return pData;
17 }
18 return NULL;
19 }
20
ILGetConnName(PCITEMID_CHILD pidl)21 PWCHAR ILGetConnName(PCITEMID_CHILD pidl)
22 {
23 PNETCONIDSTRUCT pdata = ILGetConnData(pidl);
24 if (!pdata)
25 return NULL;
26 return (PWCHAR)&pidl->mkid.abID[pdata->uNameOffset];
27 }
28
ILGetDeviceName(PCITEMID_CHILD pidl)29 PWCHAR ILGetDeviceName(PCITEMID_CHILD pidl)
30 {
31 PNETCONIDSTRUCT pdata = ILGetConnData(pidl);
32 if (!pdata)
33 return NULL;
34 return (PWCHAR)&pidl->mkid.abID[pdata->uDeviceNameOffset];
35 }
36
ILCreateNetConnectItem(INetConnection * pItem)37 PITEMID_CHILD ILCreateNetConnectItem(INetConnection * pItem)
38 {
39 PITEMID_CHILD pidl;
40 ULONG_PTR size;
41 NETCON_PROPERTIES * pProperties;
42 PNETCONIDSTRUCT pnetid;
43 PWCHAR pwchName;
44
45 if (pItem->GetProperties(&pProperties) != S_OK)
46 return NULL;
47
48 size = sizeof(WORD); /* nr of bytes in this item */
49 size += sizeof(NETCONIDSTRUCT);
50 size += (wcslen(pProperties->pszwName) + 1) * sizeof(WCHAR);
51 size += (wcslen(pProperties->pszwDeviceName) + 1) * sizeof(WCHAR);
52
53 /* Allocate enough memory for the trailing id which will indicate that this is a simple id */
54 pidl = static_cast<LPITEMIDLIST>(SHAlloc(size + sizeof(SHITEMID)));
55 if (!pidl)
56 goto end;
57 pidl->mkid.cb = (WORD)size;
58 ((PNETCONIDSTRUCT)(pidl->mkid.abID))->Signature = NETCONIDSTRUCT_SIG;
59
60 /* Copy the connection properties */
61 pnetid = ILGetConnData(pidl);
62 memset(pnetid->Unknown, 0, sizeof(pnetid->Unknown));
63 pnetid->clsidThisObject = pProperties->clsidThisObject;
64 pnetid->guidId = pProperties->guidId;
65 pnetid->Status = pProperties->Status;
66 pnetid->MediaType = pProperties->MediaType;
67 pnetid->dwCharacter = pProperties->dwCharacter;
68 pnetid->uNameOffset = sizeof(NETCONIDSTRUCT);
69 pnetid->uDeviceNameOffset = ULONG(pnetid->uNameOffset + (wcslen(pProperties->pszwName) + 1) * sizeof(WCHAR));
70
71 pwchName = ILGetConnName(pidl);
72 wcscpy(pwchName, pProperties->pszwName);
73
74 pwchName = ILGetDeviceName(pidl);
75 wcscpy(pwchName, pProperties->pszwDeviceName);
76
77 /* Set the trailing id to null */
78 memset((void*)((ULONG_PTR)pidl + size), 0, sizeof(SHITEMID));
79 end:
80 NcFreeNetconProperties(pProperties);
81
82 return pidl;
83 }
84
ILGetConnection(PCITEMID_CHILD pidl,INetConnection ** pItem)85 HRESULT ILGetConnection(PCITEMID_CHILD pidl, INetConnection ** pItem)
86 {
87 HRESULT hr;
88 CComPtr<INetConnectionManager> pNetConMan;
89 CComPtr<IEnumNetConnection> pEnumCon;
90 CComPtr<INetConnection> INetCon;
91 ULONG Count;
92 NETCON_PROPERTIES * pProperties;
93
94 PNETCONIDSTRUCT pdata = ILGetConnData(pidl);
95 if (!pdata)
96 return E_FAIL;
97
98 /* get an instance to of IConnectionManager */
99 hr = CNetConnectionManager_CreateInstance(IID_PPV_ARG(INetConnectionManager, &pNetConMan));
100 if (FAILED_UNEXPECTEDLY(hr))
101 return hr;
102
103 hr = pNetConMan->EnumConnections(NCME_DEFAULT, &pEnumCon);
104 if (FAILED_UNEXPECTEDLY(hr))
105 return hr;
106
107 while (TRUE)
108 {
109 hr = pEnumCon->Next(1, &INetCon, &Count);
110 if (hr != S_OK)
111 return E_FAIL;
112
113 hr = INetCon->GetProperties(&pProperties);
114 if (FAILED_UNEXPECTEDLY(hr))
115 continue;
116
117 BOOL bSame = !memcmp(&pProperties->guidId, &pdata->guidId, sizeof(GUID));
118
119 NcFreeNetconProperties(pProperties);
120
121 if (bSame)
122 {
123 *pItem = INetCon.Detach();
124 return S_OK;
125 }
126 }
127
128 return E_FAIL;
129 }
130
131 typedef struct tagENUMLIST
132 {
133 struct tagENUMLIST *pNext;
134 PITEMID_CHILD pidl;
135 } ENUMLIST, *LPENUMLIST;
136
137 class CEnumIDList:
138 public CComObjectRootEx<CComMultiThreadModelNoCS>,
139 public IEnumIDList
140 {
141 public:
142 CEnumIDList();
143 ~CEnumIDList();
144
145 HRESULT Initialize();
146
147 // IEnumIDList
148 STDMETHOD(Next)(ULONG celt, PITEMID_CHILD *rgelt, ULONG *pceltFetched) override;
149 STDMETHOD(Skip)(ULONG celt) override;
150 STDMETHOD(Reset)() override;
151 STDMETHOD(Clone)(IEnumIDList **ppenum) override;
152
153 private:
154 BOOL AddToEnumList(PITEMID_CHILD pidl);
155
156 LPENUMLIST m_pFirst;
157 LPENUMLIST m_pLast;
158 LPENUMLIST m_pCurrent;
159
160 public:
161 DECLARE_NOT_AGGREGATABLE(CEnumIDList)
162 DECLARE_PROTECT_FINAL_CONSTRUCT()
163
164 BEGIN_COM_MAP(CEnumIDList)
165 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
166 END_COM_MAP()
167 };
168
169 /**************************************************************************
170 * AddToEnumList()
171 */
172 BOOL
AddToEnumList(PITEMID_CHILD pidl)173 CEnumIDList::AddToEnumList(PITEMID_CHILD pidl)
174 {
175 LPENUMLIST pNew;
176
177 if (!pidl)
178 return FALSE;
179
180 pNew = static_cast<LPENUMLIST>(SHAlloc(sizeof(ENUMLIST)));
181 if (pNew)
182 {
183 pNew->pNext = NULL;
184 pNew->pidl = pidl;
185
186 if (!m_pFirst)
187 {
188 m_pFirst = pNew;
189 m_pCurrent = pNew;
190 }
191
192 if (m_pLast)
193 {
194 /*add the new item to the end of the list */
195 m_pLast->pNext = pNew;
196 }
197
198 /*update the last item pointer */
199 m_pLast = pNew;
200 return TRUE;
201 }
202 return FALSE;
203 }
204
CEnumIDList()205 CEnumIDList::CEnumIDList() :
206 m_pFirst(NULL),
207 m_pLast(NULL),
208 m_pCurrent(NULL)
209 {
210 }
211
~CEnumIDList()212 CEnumIDList::~CEnumIDList()
213 {
214 LPENUMLIST pDelete;
215
216 while (m_pFirst)
217 {
218 pDelete = m_pFirst;
219 m_pFirst = pDelete->pNext;
220 SHFree(pDelete->pidl);
221 SHFree(pDelete);
222 }
223 }
224
225 HRESULT
Initialize()226 CEnumIDList::Initialize()
227 {
228 HRESULT hr;
229 CComPtr<INetConnectionManager> pNetConMan;
230 CComPtr<IEnumNetConnection> pEnumCon;
231 ULONG Count;
232 PITEMID_CHILD pidl;
233
234 /* get an instance to of IConnectionManager */
235 hr = CNetConnectionManager_CreateInstance(IID_PPV_ARG(INetConnectionManager, &pNetConMan));
236 if (FAILED_UNEXPECTEDLY(hr))
237 return S_OK;
238
239 hr = pNetConMan->EnumConnections(NCME_DEFAULT, &pEnumCon);
240 if (FAILED_UNEXPECTEDLY(hr))
241 return S_OK;
242
243 while (TRUE)
244 {
245 CComPtr<INetConnection> INetCon;
246
247 hr = pEnumCon->Next(1, &INetCon, &Count);
248 if (hr != S_OK)
249 break;
250
251 pidl = ILCreateNetConnectItem(INetCon);
252 if (pidl)
253 {
254 AddToEnumList(pidl);
255 }
256 }
257
258 return S_OK;
259 }
260
261 HRESULT
262 WINAPI
Next(ULONG celt,PITEMID_CHILD * rgelt,ULONG * pceltFetched)263 CEnumIDList::Next(
264 ULONG celt,
265 PITEMID_CHILD *rgelt,
266 ULONG *pceltFetched)
267 {
268 ULONG i;
269 HRESULT hr = S_OK;
270 PITEMID_CHILD temp;
271
272 if (pceltFetched)
273 *pceltFetched = 0;
274
275 if (celt > 1 && !pceltFetched)
276 {
277 return E_INVALIDARG;
278 }
279
280 if (celt > 0 && !m_pCurrent)
281 {
282 return S_FALSE;
283 }
284
285 for (i = 0; i < celt; i++)
286 {
287 if (!m_pCurrent)
288 {
289 hr = S_FALSE;
290 break;
291 }
292
293 temp = ILClone(m_pCurrent->pidl);
294 if (!temp)
295 {
296 hr = i ? S_FALSE : E_OUTOFMEMORY;
297 break;
298 }
299 rgelt[i] = temp;
300 m_pCurrent = m_pCurrent->pNext;
301 }
302
303 if (pceltFetched)
304 *pceltFetched = i;
305
306 return hr;
307 }
308
309 HRESULT
310 WINAPI
Skip(ULONG celt)311 CEnumIDList::Skip(ULONG celt)
312 {
313 DWORD dwIndex;
314 HRESULT hr = S_OK;
315
316 for (dwIndex = 0; dwIndex < celt; dwIndex++)
317 {
318 if (!m_pCurrent)
319 {
320 hr = S_FALSE;
321 break;
322 }
323 m_pCurrent = m_pCurrent->pNext;
324 }
325
326 return hr;
327 }
328
329 HRESULT
330 WINAPI
Reset()331 CEnumIDList::Reset()
332 {
333 m_pCurrent = m_pFirst;
334 return S_OK;
335 }
336
337 HRESULT
338 WINAPI
Clone(LPENUMIDLIST * ppenum)339 CEnumIDList::Clone(
340 LPENUMIDLIST * ppenum)
341 {
342 return E_NOTIMPL;
343 }
344
CEnumIDList_CreateInstance(HWND hwndOwner,DWORD dwFlags,REFIID riid,LPVOID * ppv)345 HRESULT CEnumIDList_CreateInstance(HWND hwndOwner, DWORD dwFlags, REFIID riid, LPVOID * ppv)
346 {
347 return ShellObjectCreatorInit<CEnumIDList>(riid, ppv);
348 }
349