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