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