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