c43624e6337bfb2f604154ba598837aa82e16fcf
[reactos.git] / reactos / 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 return E_NOTIMPL;
333 }
334
335 HRESULT WINAPI IConnection_Constructor(INetConnection **ppv, PINetConnectionItem pItem)
336 {
337 if (!ppv)
338 return E_POINTER;
339
340 CNetConnection *pConnection = new CNetConnection(pItem);
341 if (!pConnection)
342 return E_OUTOFMEMORY;
343
344 pConnection->AddRef();
345 *ppv = (INetConnection *)pConnection;
346
347 return S_OK;
348 }
349
350
351 /***************************************************************
352 * IEnumNetConnection Interface
353 */
354
355 HRESULT
356 WINAPI
357 CNetConnectionManager::Next(
358 ULONG celt,
359 INetConnection **rgelt,
360 ULONG *pceltFetched)
361 {
362 HRESULT hr;
363
364 if (!pceltFetched || !rgelt)
365 return E_POINTER;
366
367 if (celt != 1)
368 return E_FAIL;
369
370 if (!pCurrent)
371 return S_FALSE;
372
373 hr = IConnection_Constructor(rgelt, pCurrent);
374 pCurrent = pCurrent->Next;
375
376 return hr;
377 }
378
379 HRESULT
380 WINAPI
381 CNetConnectionManager::Skip(ULONG celt)
382 {
383 while(pCurrent && celt-- > 0)
384 pCurrent = pCurrent->Next;
385
386 if (celt)
387 return S_FALSE;
388 else
389 return S_OK;
390
391 }
392
393 HRESULT
394 WINAPI
395 CNetConnectionManager::Reset()
396 {
397 pCurrent = pHead;
398 return S_OK;
399 }
400
401 HRESULT
402 WINAPI
403 CNetConnectionManager::Clone(IEnumNetConnection **ppenum)
404 {
405 return E_NOTIMPL;
406 }
407
408 BOOL
409 GetAdapterIndexFromNetCfgInstanceId(PIP_ADAPTER_INFO pAdapterInfo, LPWSTR szNetCfg, PDWORD pIndex)
410 {
411 WCHAR szBuffer[50];
412 IP_ADAPTER_INFO * pCurrentAdapter;
413
414 pCurrentAdapter = pAdapterInfo;
415 while(pCurrentAdapter)
416 {
417 szBuffer[0] = L'\0';
418 if (MultiByteToWideChar(CP_ACP, 0, pCurrentAdapter->AdapterName, -1, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0])))
419 {
420 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
421 }
422 if (!_wcsicmp(szBuffer, szNetCfg))
423 {
424 *pIndex = pCurrentAdapter->Index;
425 return TRUE;
426 }
427 pCurrentAdapter = pCurrentAdapter->Next;
428 }
429 return FALSE;
430 }
431
432 VOID
433 NormalizeOperStatus(
434 MIB_IFROW *IfEntry,
435 NETCON_PROPERTIES * Props)
436 {
437 switch(IfEntry->dwOperStatus)
438 {
439 case MIB_IF_OPER_STATUS_NON_OPERATIONAL:
440 Props->Status = NCS_HARDWARE_DISABLED;
441 break;
442 case MIB_IF_OPER_STATUS_UNREACHABLE:
443 Props->Status = NCS_DISCONNECTED;
444 break;
445 case MIB_IF_OPER_STATUS_DISCONNECTED:
446 Props->Status = NCS_MEDIA_DISCONNECTED;
447 break;
448 case MIB_IF_OPER_STATUS_CONNECTING:
449 Props->Status = NCS_CONNECTING;
450 break;
451 case MIB_IF_OPER_STATUS_CONNECTED:
452 Props->Status = NCS_CONNECTED;
453 break;
454 case MIB_IF_OPER_STATUS_OPERATIONAL:
455 Props->Status = NCS_CONNECTED;
456 break;
457 default:
458 break;
459 }
460 }
461
462 BOOL
463 CNetConnectionManager::EnumerateINetConnections()
464 {
465 DWORD dwSize, dwResult, dwIndex, dwAdapterIndex, dwShowIcon;
466 MIB_IFTABLE *pIfTable;
467 MIB_IFROW IfEntry;
468 IP_ADAPTER_INFO * pAdapterInfo;
469 HDEVINFO hInfo;
470 SP_DEVINFO_DATA DevInfo;
471 HKEY hSubKey;
472 WCHAR szNetCfg[50];
473 WCHAR szAdapterNetCfg[50];
474 WCHAR szDetail[200] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\";
475 WCHAR szName[130] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
476 PINetConnectionItem pCurrent = NULL;
477
478 /* get the IfTable */
479 dwSize = 0;
480 if (GetIfTable(NULL, &dwSize, TRUE) != ERROR_INSUFFICIENT_BUFFER)
481 return FALSE;
482
483 pIfTable = (PMIB_IFTABLE)CoTaskMemAlloc(dwSize);
484 if (!pIfTable)
485 return FALSE;
486
487 dwResult = GetIfTable(pIfTable, &dwSize, TRUE);
488 if (dwResult != NO_ERROR)
489 {
490 CoTaskMemFree(pIfTable);
491 return FALSE;
492 }
493
494 dwSize = 0;
495 dwResult = GetAdaptersInfo(NULL, &dwSize);
496 if (dwResult!= ERROR_BUFFER_OVERFLOW)
497 {
498 CoTaskMemFree(pIfTable);
499 return FALSE;
500 }
501
502 pAdapterInfo = (PIP_ADAPTER_INFO)CoTaskMemAlloc(dwSize);
503 if (!pAdapterInfo)
504 {
505 CoTaskMemFree(pIfTable);
506 return FALSE;
507 }
508
509 if (GetAdaptersInfo(pAdapterInfo, &dwSize) != NO_ERROR)
510 {
511 CoTaskMemFree(pIfTable);
512 CoTaskMemFree(pAdapterInfo);
513 return FALSE;
514 }
515
516 hInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT );
517 if (!hInfo)
518 {
519 CoTaskMemFree(pIfTable);
520 CoTaskMemFree(pAdapterInfo);
521 return FALSE;
522 }
523
524 dwIndex = 0;
525 do
526 {
527 ZeroMemory(&DevInfo, sizeof(SP_DEVINFO_DATA));
528 DevInfo.cbSize = sizeof(DevInfo);
529
530 /* get device info */
531 if (!SetupDiEnumDeviceInfo(hInfo, dwIndex++, &DevInfo))
532 break;
533
534 /* get device software registry path */
535 if (!SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DRIVER, NULL, (LPBYTE)&szDetail[39], sizeof(szDetail)/sizeof(WCHAR) - 40, &dwSize))
536 break;
537
538 /* open device registry key */
539 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szDetail, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
540 break;
541
542 /* query NetCfgInstanceId for current device */
543 dwSize = sizeof(szNetCfg);
544 if (RegQueryValueExW(hSubKey, L"NetCfgInstanceId", NULL, NULL, (LPBYTE)szNetCfg, &dwSize) != ERROR_SUCCESS)
545 {
546 RegCloseKey(hSubKey);
547 break;
548 }
549 RegCloseKey(hSubKey);
550
551 /* get the current adapter index from NetCfgInstanceId */
552 if (!GetAdapterIndexFromNetCfgInstanceId(pAdapterInfo, szNetCfg, &dwAdapterIndex))
553 continue;
554
555 /* get detailed adapter info */
556 ZeroMemory(&IfEntry, sizeof(IfEntry));
557 IfEntry.dwIndex = dwAdapterIndex;
558 if(GetIfEntry(&IfEntry) != NO_ERROR)
559 break;
560
561 /* allocate new INetConnectionItem */
562 PINetConnectionItem pNew = (PINetConnectionItem)CoTaskMemAlloc(sizeof(INetConnectionItem));
563 if (!pNew)
564 break;
565
566 ZeroMemory(pNew, sizeof(INetConnectionItem));
567 pNew->dwAdapterIndex = dwAdapterIndex;
568 /* store NetCfgInstanceId */
569 CLSIDFromString(szNetCfg, &pNew->Props.guidId);
570 NormalizeOperStatus(&IfEntry, &pNew->Props);
571
572 switch(IfEntry.dwType)
573 {
574 case IF_TYPE_ETHERNET_CSMACD:
575 pNew->Props.MediaType = NCM_LAN;
576 break;
577 case IF_TYPE_IEEE80211:
578 pNew->Props.MediaType = NCM_SHAREDACCESSHOST_RAS;
579 break;
580 default:
581 break;
582 }
583 /* open network connections details */
584 wcscpy(&szName[80], szNetCfg);
585 wcscpy(&szName[118], L"\\Connection");
586
587 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
588 {
589 /* retrieve name of connection */
590 dwSize = sizeof(szAdapterNetCfg);
591 if (RegQueryValueExW(hSubKey, L"Name", NULL, NULL, (LPBYTE)szAdapterNetCfg, &dwSize) == ERROR_SUCCESS)
592 {
593 pNew->Props.pszwName = (LPWSTR)CoTaskMemAlloc((wcslen(szAdapterNetCfg)+1) * sizeof(WCHAR));
594 if (pNew->Props.pszwName)
595 wcscpy(pNew->Props.pszwName, szAdapterNetCfg);
596 }
597 dwSize = sizeof(dwShowIcon);
598 if (RegQueryValueExW(hSubKey, L"ShowIcon", NULL, NULL, (LPBYTE)&dwShowIcon, &dwSize) == ERROR_SUCCESS)
599 {
600 if (dwShowIcon)
601 pNew->Props.dwCharacter |= NCCF_SHOW_ICON;
602 }
603 RegCloseKey(hSubKey);
604 }
605
606 /* Get the adapter device description */
607 dwSize = 0;
608 SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DEVICEDESC, NULL, NULL, 0, &dwSize);
609 if (dwSize != 0)
610 {
611 pNew->Props.pszwDeviceName = (LPWSTR)CoTaskMemAlloc(dwSize);
612 if (pNew->Props.pszwDeviceName)
613 SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DEVICEDESC, NULL, (PBYTE)pNew->Props.pszwDeviceName, dwSize, &dwSize);
614 }
615
616 if (pCurrent)
617 pCurrent->Next = pNew;
618 else
619 pHead = pNew;
620
621 pCurrent = pNew;
622 }while(TRUE);
623
624 CoTaskMemFree(pIfTable);
625 CoTaskMemFree(pAdapterInfo);
626 SetupDiDestroyDeviceInfoList(hInfo);
627
628 this->pCurrent = pHead;
629 return TRUE;
630 }
631
632 HRESULT WINAPI INetConnectionManager_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID * ppv)
633 {
634 TRACE("INetConnectionManager_Constructor\n");
635
636 if (!ppv)
637 return E_POINTER;
638 if (pUnkOuter)
639 return CLASS_E_NOAGGREGATION;
640
641 CNetConnectionManager *pConnectionMgr = new CNetConnectionManager;
642 if (!pConnectionMgr)
643 return E_OUTOFMEMORY;
644
645 pConnectionMgr->AddRef();
646 HRESULT hr = pConnectionMgr->QueryInterface(riid, ppv);
647
648 if (SUCCEEDED(hr))
649 pConnectionMgr->EnumerateINetConnections();
650
651 pConnectionMgr->Release();
652
653 return hr;
654 }
655
656