1 /*
2  * PROJECT:     ReactOS Shell
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     CNetConnectionManager class
5  * COPYRIGHT:   Copyright 2008 Johannes Anderwald (johannes.anderwald@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 VOID NormalizeOperStatus(MIB_IFROW *IfEntry, NETCON_PROPERTIES * Props);
11 
12 /***************************************************************
13  * INetConnection Interface
14  */
15 
16 HRESULT
17 WINAPI
18 CNetConnection::Initialize(PINetConnectionItem pItem)
19 {
20     m_Props = pItem->Props;
21     m_dwAdapterIndex = pItem->dwAdapterIndex;
22 
23     if (pItem->Props.pszwName)
24     {
25         m_Props.pszwName = static_cast<PWSTR>(CoTaskMemAlloc((wcslen(pItem->Props.pszwName)+1)*sizeof(WCHAR)));
26         if (m_Props.pszwName)
27             wcscpy(m_Props.pszwName, pItem->Props.pszwName);
28     }
29 
30     if (pItem->Props.pszwDeviceName)
31     {
32         m_Props.pszwDeviceName = static_cast<PWSTR>(CoTaskMemAlloc((wcslen(pItem->Props.pszwDeviceName)+1)*sizeof(WCHAR)));
33         if (m_Props.pszwDeviceName)
34             wcscpy(m_Props.pszwDeviceName, pItem->Props.pszwDeviceName);
35     }
36 
37     return S_OK;
38 }
39 
40 CNetConnection::~CNetConnection()
41 {
42     CoTaskMemFree(m_Props.pszwName);
43     CoTaskMemFree(m_Props.pszwDeviceName);
44 }
45 
46 HRESULT
47 WINAPI
48 CNetConnection::Connect()
49 {
50     return E_NOTIMPL;
51 }
52 
53 BOOL
54 FindNetworkAdapter(HDEVINFO hInfo, SP_DEVINFO_DATA *pDevInfo, LPWSTR pGuid)
55 {
56     DWORD dwIndex, dwSize;
57     HKEY hSubKey;
58     WCHAR szNetCfg[50];
59     WCHAR szDetail[200] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\";
60 
61     dwIndex = 0;
62     do
63     {
64         ZeroMemory(pDevInfo, sizeof(SP_DEVINFO_DATA));
65         pDevInfo->cbSize = sizeof(SP_DEVINFO_DATA);
66 
67         /* get device info */
68         if (!SetupDiEnumDeviceInfo(hInfo, dwIndex++, pDevInfo))
69             break;
70 
71         /* get device software registry path */
72         if (!SetupDiGetDeviceRegistryPropertyW(hInfo, pDevInfo, SPDRP_DRIVER, NULL, (LPBYTE)&szDetail[39], sizeof(szDetail)/sizeof(WCHAR) - 40, &dwSize))
73             break;
74 
75         /* open device registry key */
76         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szDetail, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
77             break;
78 
79         /* query NetCfgInstanceId for current device */
80         dwSize = sizeof(szNetCfg);
81         if (RegQueryValueExW(hSubKey, L"NetCfgInstanceId", NULL, NULL, (LPBYTE)szNetCfg, &dwSize) != ERROR_SUCCESS)
82         {
83             RegCloseKey(hSubKey);
84             break;
85         }
86         RegCloseKey(hSubKey);
87         if (!_wcsicmp(pGuid, szNetCfg))
88         {
89             return TRUE;
90         }
91     } while (TRUE);
92 
93     return FALSE;
94 }
95 
96 HRESULT
97 WINAPI
98 CNetConnection::Disconnect()
99 {
100     HKEY hKey;
101     NETCON_PROPERTIES * pProperties;
102     LPOLESTR pDisplayName;
103     WCHAR szPath[200];
104     DWORD dwSize, dwType;
105     LPWSTR pPnp;
106     HDEVINFO hInfo;
107     SP_DEVINFO_DATA DevInfo;
108     SP_PROPCHANGE_PARAMS PropChangeParams;
109     HRESULT hr;
110 
111     hr = GetProperties(&pProperties);
112     if (FAILED_UNEXPECTEDLY(hr))
113         return hr;
114 
115     hInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT );
116     if (!hInfo)
117     {
118         NcFreeNetconProperties(pProperties);
119         return E_FAIL;
120     }
121 
122     if (FAILED(StringFromCLSID((CLSID)pProperties->guidId, &pDisplayName)))
123     {
124         NcFreeNetconProperties(pProperties);
125         SetupDiDestroyDeviceInfoList(hInfo);
126         return E_FAIL;
127     }
128     NcFreeNetconProperties(pProperties);
129 
130     if (FindNetworkAdapter(hInfo, &DevInfo, pDisplayName))
131     {
132         PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
133         PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; //;
134         PropChangeParams.StateChange = DICS_DISABLE;
135         PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;
136         PropChangeParams.HwProfile = 0;
137 
138         if (!SetupDiSetClassInstallParams(hInfo, &DevInfo, &PropChangeParams.ClassInstallHeader, sizeof(SP_PROPCHANGE_PARAMS)) ||
139             !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hInfo, &DevInfo))
140         {
141             hr = HRESULT_FROM_WIN32(GetLastError());
142         }
143     }
144     SetupDiDestroyDeviceInfoList(hInfo);
145 
146     swprintf(szPath, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", pDisplayName);
147     CoTaskMemFree(pDisplayName);
148 
149     if (FAILED_UNEXPECTEDLY(hr))
150         return hr;
151 
152     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
153         return E_FAIL;
154 
155     dwSize = 0;
156     if (RegQueryValueExW(hKey, L"PnpInstanceID", NULL, &dwType, NULL, &dwSize) != ERROR_SUCCESS || dwType != REG_SZ)
157     {
158         RegCloseKey(hKey);
159         return E_FAIL;
160     }
161 
162     pPnp = static_cast<PWSTR>(CoTaskMemAlloc(dwSize));
163     if (!pPnp)
164     {
165         RegCloseKey(hKey);
166         return E_FAIL;
167     }
168 
169     if (RegQueryValueExW(hKey, L"PnpInstanceID", NULL, &dwType, (LPBYTE)pPnp, &dwSize) != ERROR_SUCCESS)
170     {
171         CoTaskMemFree(pPnp);
172         RegCloseKey(hKey);
173         return E_FAIL;
174     }
175     RegCloseKey(hKey);
176 
177     swprintf(szPath, L"System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Enum\\%s", pPnp);
178     CoTaskMemFree(pPnp);
179 
180     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szPath, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
181         return E_FAIL;
182 
183     dwSize = 1; /* enable = 0, disable = 1 */
184     RegSetValueExW(hKey, L"CSConfigFlags", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD));
185     RegCloseKey(hKey);
186 
187     return S_OK;
188 }
189 
190 HRESULT
191 WINAPI
192 CNetConnection::Delete()
193 {
194     return E_NOTIMPL;
195 }
196 
197 HRESULT
198 WINAPI
199 CNetConnection::Duplicate(
200     LPCWSTR pszwDuplicateName,
201     INetConnection **ppCon)
202 {
203     return E_NOTIMPL;
204 }
205 
206 HRESULT
207 WINAPI
208 CNetConnection::GetProperties(NETCON_PROPERTIES **ppProps)
209 {
210     MIB_IFROW IfEntry;
211     HKEY hKey;
212     LPOLESTR pStr;
213     WCHAR szName[140];
214     DWORD dwShowIcon, dwNotifyDisconnect, dwType, dwSize;
215     NETCON_PROPERTIES * pProperties;
216     HRESULT hr;
217 
218     if (!ppProps)
219         return E_POINTER;
220 
221     pProperties = static_cast<NETCON_PROPERTIES*>(CoTaskMemAlloc(sizeof(NETCON_PROPERTIES)));
222     if (!pProperties)
223         return E_OUTOFMEMORY;
224 
225     CopyMemory(pProperties, &m_Props, sizeof(NETCON_PROPERTIES));
226     pProperties->pszwName = NULL;
227 
228     if (m_Props.pszwDeviceName)
229     {
230         pProperties->pszwDeviceName = static_cast<LPWSTR>(CoTaskMemAlloc((wcslen(m_Props.pszwDeviceName)+1)*sizeof(WCHAR)));
231         if (pProperties->pszwDeviceName)
232             wcscpy(pProperties->pszwDeviceName, m_Props.pszwDeviceName);
233     }
234 
235     *ppProps = pProperties;
236 
237     /* get updated adapter characteristics */
238     ZeroMemory(&IfEntry, sizeof(IfEntry));
239     IfEntry.dwIndex = m_dwAdapterIndex;
240     if (GetIfEntry(&IfEntry) != NO_ERROR)
241         return NOERROR;
242 
243     NormalizeOperStatus(&IfEntry, pProperties);
244 
245 
246     hr = StringFromCLSID((CLSID)m_Props.guidId, &pStr);
247     if (SUCCEEDED(hr))
248     {
249         wcscpy(szName, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\");
250         wcscat(szName, pStr);
251         wcscat(szName, L"\\Connection");
252 
253         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
254         {
255             dwSize = sizeof(dwShowIcon);
256             if (RegQueryValueExW(hKey, L"ShowIcon", NULL, &dwType, (LPBYTE)&dwShowIcon, &dwSize) == ERROR_SUCCESS && dwType == REG_DWORD)
257             {
258                 if (dwShowIcon)
259                     pProperties->dwCharacter |= NCCF_SHOW_ICON;
260                 else
261                     pProperties->dwCharacter &= ~NCCF_SHOW_ICON;
262             }
263 
264             dwSize = sizeof(dwNotifyDisconnect);
265             if (RegQueryValueExW(hKey, L"IpCheckingEnabled", NULL, &dwType, (LPBYTE)&dwNotifyDisconnect, &dwSize) == ERROR_SUCCESS && dwType == REG_DWORD)
266             {
267                 if (dwNotifyDisconnect)
268                     pProperties->dwCharacter |= NCCF_NOTIFY_DISCONNECTED;
269                 else
270                     pProperties->dwCharacter &= ~NCCF_NOTIFY_DISCONNECTED;
271             }
272 
273             dwSize = sizeof(szName);
274             if (RegQueryValueExW(hKey, L"Name", NULL, &dwType, (LPBYTE)szName, &dwSize) == ERROR_SUCCESS)
275             {
276                 /* use updated name */
277                 dwSize = wcslen(szName) + 1;
278                 pProperties->pszwName = static_cast<PWSTR>(CoTaskMemAlloc(dwSize * sizeof(WCHAR)));
279                 if (pProperties->pszwName)
280                     CopyMemory(pProperties->pszwName, szName, dwSize * sizeof(WCHAR));
281             }
282             else
283             {
284                 /* use cached name */
285                 if (m_Props.pszwName)
286                 {
287                     pProperties->pszwName = static_cast<PWSTR>(CoTaskMemAlloc((wcslen(m_Props.pszwName)+1)*sizeof(WCHAR)));
288                     if (pProperties->pszwName)
289                         wcscpy(pProperties->pszwName, m_Props.pszwName);
290                 }
291             }
292             RegCloseKey(hKey);
293         }
294         CoTaskMemFree(pStr);
295     }
296 
297     /* Enable 'Rename' and 'Delete' for Adminstrators only */
298     if (IsUserAdmin())
299     {
300         pProperties->dwCharacter |= NCCF_ALLOW_RENAME;
301 
302         /* Virtual network interfaces can be deleted */
303         if (IfEntry.dwType == IF_TYPE_TUNNEL)
304         {
305             pProperties->dwCharacter |= NCCF_ALLOW_REMOVAL;
306         }
307     }
308     else
309     {
310         pProperties->dwCharacter &= ~(NCCF_ALLOW_RENAME | NCCF_ALLOW_REMOVAL);
311     }
312 
313     return S_OK;
314 }
315 
316 HRESULT
317 WINAPI
318 CNetConnection::GetUiObjectClassId(CLSID *pclsid)
319 {
320     if (m_Props.MediaType == NCM_LAN)
321     {
322         CopyMemory(pclsid, &CLSID_LanConnectionUi, sizeof(CLSID));
323         return S_OK;
324     }
325 
326     return E_NOTIMPL;
327 }
328 
329 HRESULT
330 WINAPI
331 CNetConnection::Rename(LPCWSTR pszwDuplicateName)
332 {
333     WCHAR szName[140];
334     LPOLESTR pStr;
335     DWORD dwSize;
336     HKEY hKey;
337     HRESULT hr;
338 
339     if (pszwDuplicateName == NULL || wcslen(pszwDuplicateName) == 0)
340         return S_OK;
341 
342     if (m_Props.pszwName)
343     {
344         CoTaskMemFree(m_Props.pszwName);
345         m_Props.pszwName = NULL;
346     }
347 
348     dwSize = (wcslen(pszwDuplicateName) + 1) * sizeof(WCHAR);
349     m_Props.pszwName = static_cast<PWSTR>(CoTaskMemAlloc(dwSize));
350     if (m_Props.pszwName == NULL)
351         return E_OUTOFMEMORY;
352 
353     wcscpy(m_Props.pszwName, pszwDuplicateName);
354 
355     hr = StringFromCLSID((CLSID)m_Props.guidId, &pStr);
356     if (SUCCEEDED(hr))
357     {
358         wcscpy(szName, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\");
359         wcscat(szName, pStr);
360         wcscat(szName, L"\\Connection");
361 
362         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
363         {
364             RegSetValueExW(hKey, L"Name", NULL, REG_SZ, (LPBYTE)m_Props.pszwName, dwSize);
365             RegCloseKey(hKey);
366         }
367 
368         CoTaskMemFree(pStr);
369     }
370 
371     return hr;
372 }
373 
374 HRESULT WINAPI CNetConnection_CreateInstance(PINetConnectionItem pItem, REFIID riid, LPVOID * ppv)
375 {
376     return ShellObjectCreatorInit<CNetConnection>(pItem, riid, ppv);
377 }
378 
379 
380 
381 CNetConnectionManager::CNetConnectionManager() :
382     m_pHead(NULL),
383     m_pCurrent(NULL)
384 {
385 }
386 
387 HRESULT
388 WINAPI
389 CNetConnectionManager::EnumConnections(
390     NETCONMGR_ENUM_FLAGS Flags,
391     IEnumNetConnection **ppEnum)
392 {
393     TRACE("EnumConnections\n");
394 
395     if (!ppEnum)
396         return E_POINTER;
397 
398     if (Flags != NCME_DEFAULT)
399         return E_FAIL;
400 
401     *ppEnum = static_cast<IEnumNetConnection*>(this);
402     AddRef();
403     return S_OK;
404 }
405 
406 /***************************************************************
407  * IEnumNetConnection Interface
408  */
409 
410 HRESULT
411 WINAPI
412 CNetConnectionManager::Next(
413     ULONG celt,
414     INetConnection **rgelt,
415     ULONG *pceltFetched)
416 {
417     HRESULT hr;
418 
419     if (!pceltFetched || !rgelt)
420         return E_POINTER;
421 
422     if (celt != 1)
423         return E_FAIL;
424 
425     if (!m_pCurrent)
426         return S_FALSE;
427 
428     hr = CNetConnection_CreateInstance(m_pCurrent, IID_PPV_ARG(INetConnection, rgelt));
429     m_pCurrent = m_pCurrent->Next;
430 
431     return hr;
432 }
433 
434 HRESULT
435 WINAPI
436 CNetConnectionManager::Skip(ULONG celt)
437 {
438     while (m_pCurrent && celt-- > 0)
439         m_pCurrent = m_pCurrent->Next;
440 
441     if (celt)
442        return S_FALSE;
443     else
444        return S_OK;
445 
446 }
447 
448 HRESULT
449 WINAPI
450 CNetConnectionManager::Reset()
451 {
452     m_pCurrent = m_pHead;
453     return S_OK;
454 }
455 
456 HRESULT
457 WINAPI
458 CNetConnectionManager::Clone(IEnumNetConnection **ppenum)
459 {
460     return E_NOTIMPL;
461 }
462 
463 BOOL
464 GetAdapterIndexFromNetCfgInstanceId(PIP_ADAPTER_INFO pAdapterInfo, LPWSTR szNetCfg, PDWORD pIndex)
465 {
466     WCHAR szBuffer[50];
467     IP_ADAPTER_INFO * pCurrentAdapter;
468 
469     pCurrentAdapter = pAdapterInfo;
470     while (pCurrentAdapter)
471     {
472         szBuffer[0] = L'\0';
473         if (MultiByteToWideChar(CP_ACP, 0, pCurrentAdapter->AdapterName, -1, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0])))
474         {
475             szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
476         }
477         if (!_wcsicmp(szBuffer, szNetCfg))
478         {
479             *pIndex = pCurrentAdapter->Index;
480             return TRUE;
481         }
482         pCurrentAdapter = pCurrentAdapter->Next;
483     }
484     return FALSE;
485 }
486 
487 VOID
488 NormalizeOperStatus(
489     MIB_IFROW *IfEntry,
490     NETCON_PROPERTIES    * Props)
491 {
492     switch (IfEntry->dwOperStatus)
493     {
494         case MIB_IF_OPER_STATUS_NON_OPERATIONAL:
495             Props->Status = NCS_HARDWARE_DISABLED;
496             break;
497         case MIB_IF_OPER_STATUS_UNREACHABLE:
498             Props->Status = NCS_DISCONNECTED;
499             break;
500         case MIB_IF_OPER_STATUS_DISCONNECTED:
501             Props->Status = NCS_MEDIA_DISCONNECTED;
502             break;
503         case MIB_IF_OPER_STATUS_CONNECTING:
504             Props->Status = NCS_CONNECTING;
505             break;
506         case MIB_IF_OPER_STATUS_CONNECTED:
507             Props->Status = NCS_CONNECTED;
508             break;
509         case MIB_IF_OPER_STATUS_OPERATIONAL:
510             Props->Status = NCS_CONNECTED;
511             break;
512         default:
513             break;
514     }
515 }
516 
517 HRESULT
518 CNetConnectionManager::EnumerateINetConnections()
519 {
520     DWORD dwSize, dwResult, dwIndex, dwAdapterIndex, dwShowIcon, dwNotifyDisconnect;
521     MIB_IFTABLE *pIfTable;
522     MIB_IFROW IfEntry;
523     IP_ADAPTER_INFO * pAdapterInfo;
524     HDEVINFO hInfo;
525     SP_DEVINFO_DATA DevInfo;
526     HKEY hSubKey;
527     WCHAR szNetCfg[50];
528     WCHAR szAdapterNetCfg[50];
529     WCHAR szDetail[200] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\";
530     WCHAR szName[130] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
531     PINetConnectionItem pCurrent = NULL;
532 
533     /* get the IfTable */
534     dwSize = 0;
535     if (GetIfTable(NULL, &dwSize, TRUE) != ERROR_INSUFFICIENT_BUFFER)
536         return E_FAIL;
537 
538     pIfTable = static_cast<PMIB_IFTABLE>(CoTaskMemAlloc(dwSize));
539     if (!pIfTable)
540         return E_OUTOFMEMORY;
541 
542     dwResult = GetIfTable(pIfTable, &dwSize, TRUE);
543     if (dwResult != NO_ERROR)
544     {
545         CoTaskMemFree(pIfTable);
546         return HRESULT_FROM_WIN32(dwResult);
547     }
548 
549     dwSize = 0;
550     dwResult = GetAdaptersInfo(NULL, &dwSize);
551     if (dwResult!= ERROR_BUFFER_OVERFLOW)
552     {
553         CoTaskMemFree(pIfTable);
554         return HRESULT_FROM_WIN32(dwResult);
555     }
556 
557     pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
558     if (!pAdapterInfo)
559     {
560         CoTaskMemFree(pIfTable);
561         return E_OUTOFMEMORY;
562     }
563 
564     dwResult = GetAdaptersInfo(pAdapterInfo, &dwSize);
565     if (dwResult != NO_ERROR)
566     {
567         CoTaskMemFree(pIfTable);
568         CoTaskMemFree(pAdapterInfo);
569         return HRESULT_FROM_WIN32(dwResult);
570     }
571 
572     hInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT );
573     if (!hInfo)
574     {
575         CoTaskMemFree(pIfTable);
576         CoTaskMemFree(pAdapterInfo);
577         return E_FAIL;
578     }
579 
580     dwIndex = 0;
581     do
582     {
583         ZeroMemory(&DevInfo, sizeof(SP_DEVINFO_DATA));
584         DevInfo.cbSize = sizeof(DevInfo);
585 
586         /* get device info */
587         if (!SetupDiEnumDeviceInfo(hInfo, dwIndex++, &DevInfo))
588             break;
589 
590         /* get device software registry path */
591         if (!SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DRIVER, NULL, (LPBYTE)&szDetail[39], sizeof(szDetail)/sizeof(WCHAR) - 40, &dwSize))
592             break;
593 
594         /* open device registry key */
595         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szDetail, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
596             break;
597 
598         /* query NetCfgInstanceId for current device */
599         dwSize = sizeof(szNetCfg);
600         if (RegQueryValueExW(hSubKey, L"NetCfgInstanceId", NULL, NULL, (LPBYTE)szNetCfg, &dwSize) != ERROR_SUCCESS)
601         {
602             RegCloseKey(hSubKey);
603             break;
604         }
605         RegCloseKey(hSubKey);
606 
607         /* get the current adapter index from NetCfgInstanceId */
608         if (!GetAdapterIndexFromNetCfgInstanceId(pAdapterInfo, szNetCfg, &dwAdapterIndex))
609             continue;
610 
611         /* get detailed adapter info */
612         ZeroMemory(&IfEntry, sizeof(IfEntry));
613         IfEntry.dwIndex = dwAdapterIndex;
614         if (GetIfEntry(&IfEntry) != NO_ERROR)
615             break;
616 
617         /* allocate new INetConnectionItem */
618         PINetConnectionItem pNew = static_cast<PINetConnectionItem>(CoTaskMemAlloc(sizeof(INetConnectionItem)));
619         if (!pNew)
620             break;
621 
622         ZeroMemory(pNew, sizeof(INetConnectionItem));
623         pNew->dwAdapterIndex = dwAdapterIndex;
624         /* store NetCfgInstanceId */
625         CLSIDFromString(szNetCfg, &pNew->Props.guidId);
626         NormalizeOperStatus(&IfEntry, &pNew->Props);
627 
628         switch (IfEntry.dwType)
629         {
630             case IF_TYPE_ETHERNET_CSMACD:
631                 pNew->Props.MediaType = NCM_LAN;
632                 break;
633             case IF_TYPE_IEEE80211:
634                 pNew->Props.MediaType = NCM_SHAREDACCESSHOST_RAS;
635                 break;
636             default:
637                 break;
638         }
639         /*  open network connections details */
640         wcscpy(&szName[80], szNetCfg);
641         wcscpy(&szName[118], L"\\Connection");
642 
643         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
644         {
645             /* retrieve name of connection */
646             dwSize = sizeof(szAdapterNetCfg);
647             if (RegQueryValueExW(hSubKey, L"Name", NULL, NULL, (LPBYTE)szAdapterNetCfg, &dwSize) == ERROR_SUCCESS)
648             {
649                 pNew->Props.pszwName = static_cast<PWSTR>(CoTaskMemAlloc((wcslen(szAdapterNetCfg)+1) * sizeof(WCHAR)));
650                 if (pNew->Props.pszwName)
651                     wcscpy(pNew->Props.pszwName, szAdapterNetCfg);
652             }
653             dwSize = sizeof(dwShowIcon);
654             if (RegQueryValueExW(hSubKey, L"ShowIcon", NULL, NULL, (LPBYTE)&dwShowIcon, &dwSize) == ERROR_SUCCESS)
655             {
656                 if (dwShowIcon)
657                     pNew->Props.dwCharacter |= NCCF_SHOW_ICON;
658             }
659             dwSize = sizeof(dwNotifyDisconnect);
660             if (RegQueryValueExW(hSubKey, L"IpCheckingEnabled", NULL, NULL, (LPBYTE)&dwNotifyDisconnect, &dwSize) == ERROR_SUCCESS)
661             {
662                 if (dwNotifyDisconnect)
663                     pNew->Props.dwCharacter |= NCCF_NOTIFY_DISCONNECTED;
664             }
665             RegCloseKey(hSubKey);
666         }
667 
668         /* Get the adapter device description */
669         dwSize = 0;
670         SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DEVICEDESC, NULL, NULL, 0, &dwSize);
671         if (dwSize != 0)
672         {
673             pNew->Props.pszwDeviceName = static_cast<PWSTR>(CoTaskMemAlloc(dwSize));
674             if (pNew->Props.pszwDeviceName)
675                 SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DEVICEDESC, NULL, (PBYTE)pNew->Props.pszwDeviceName, dwSize, &dwSize);
676         }
677 
678         if (pCurrent)
679             pCurrent->Next = pNew;
680         else
681             m_pHead = pNew;
682 
683         pCurrent = pNew;
684     } while (TRUE);
685 
686     CoTaskMemFree(pIfTable);
687     CoTaskMemFree(pAdapterInfo);
688     SetupDiDestroyDeviceInfoList(hInfo);
689 
690     m_pCurrent = m_pHead;
691     return (m_pHead != NULL ? S_OK : S_FALSE);
692 }
693 
694 HRESULT CNetConnectionManager::Initialize()
695 {
696     HRESULT hr = EnumerateINetConnections();
697     if (FAILED_UNEXPECTEDLY(hr))
698     {
699         /* If something went wrong during the enumeration print an error don't enumerate anything */
700         m_pCurrent = m_pHead = NULL;
701         return S_FALSE;
702     }
703     return S_OK;
704 }
705 
706 HRESULT WINAPI CNetConnectionManager_CreateInstance(REFIID riid, LPVOID * ppv)
707 {
708 #if USE_CUSTOM_CONMGR
709     return ShellObjectCreatorInit<CNetConnectionManager>(riid, ppv);
710 #else
711     return CoCreateInstance(CLSID_ConnectionManager, NULL, CLSCTX_ALL, riid, ppv);
712 #endif
713 }
714