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