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 break; 281 282 temp = ILClone(m_pCurrent->pidl); 283 rgelt[i] = temp; 284 m_pCurrent = m_pCurrent->pNext; 285 } 286 287 if (pceltFetched) 288 *pceltFetched = i; 289 290 return hr; 291 } 292 293 HRESULT 294 WINAPI 295 CEnumIDList::Skip(ULONG celt) 296 { 297 DWORD dwIndex; 298 HRESULT hr = S_OK; 299 300 for (dwIndex = 0; dwIndex < celt; dwIndex++) 301 { 302 if (!m_pCurrent) 303 { 304 hr = S_FALSE; 305 break; 306 } 307 m_pCurrent = m_pCurrent->pNext; 308 } 309 310 return hr; 311 } 312 313 HRESULT 314 WINAPI 315 CEnumIDList::Reset() 316 { 317 m_pCurrent = m_pFirst; 318 return S_OK; 319 } 320 321 HRESULT 322 WINAPI 323 CEnumIDList::Clone( 324 LPENUMIDLIST * ppenum) 325 { 326 return E_NOTIMPL; 327 } 328 329 HRESULT CEnumIDList_CreateInstance(HWND hwndOwner, DWORD dwFlags, REFIID riid, LPVOID * ppv) 330 { 331 return ShellObjectCreatorInit<CEnumIDList>(riid, ppv); 332 } 333