xref: /reactos/dll/shellext/netshell/enumlist.cpp (revision 4e5e72fa)
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 
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 
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 
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 
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 
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
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 
205 CEnumIDList::CEnumIDList() :
206     m_pFirst(NULL),
207     m_pLast(NULL),
208     m_pCurrent(NULL)
209 {
210 }
211 
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
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
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
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
331 CEnumIDList::Reset()
332 {
333     m_pCurrent = m_pFirst;
334     return S_OK;
335 }
336 
337 HRESULT
338 WINAPI
339 CEnumIDList::Clone(
340     LPENUMIDLIST * ppenum)
341 {
342     return E_NOTIMPL;
343 }
344 
345 HRESULT CEnumIDList_CreateInstance(HWND hwndOwner, DWORD dwFlags, REFIID riid, LPVOID * ppv)
346 {
347     return ShellObjectCreatorInit<CEnumIDList>(riid, ppv);
348 }
349