1 /*
2  * PROJECT:     ReactOS Shell
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     CLanStatus: Lan connection status dialog
5  * COPYRIGHT:   Copyright 2008 Johannes Anderwald (johannes.anderwald@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 #include <winsock.h>
11 
12 CLanStatus::CLanStatus() :
13     m_lpNetMan(NULL),
14     m_pHead(NULL)
15 {
16 }
17 
18 VOID
19 UpdateLanStatusUiDlg(
20     HWND hwndDlg,
21     MIB_IFROW *IfEntry,
22     LANSTATUSUI_CONTEXT *pContext)
23 {
24     WCHAR szFormat[MAX_PATH] = {0};
25     WCHAR szBuffer[MAX_PATH] = {0};
26     SYSTEMTIME TimeConnected;
27     DWORD DurationSeconds;
28     WCHAR Buffer[100];
29     WCHAR DayBuffer[30];
30     WCHAR LocBuffer[50];
31 
32 #if 0
33     ULONGLONG Ticks;
34 #else
35     DWORD Ticks;
36 #endif
37 
38     if (IfEntry->dwSpeed < 1000)
39     {
40         if (LoadStringW(netshell_hInstance, IDS_FORMAT_BIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
41         {
42             swprintf(szBuffer, szFormat, IfEntry->dwSpeed);
43             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
44         }
45     }
46     else if (IfEntry->dwSpeed < 1000000)
47     {
48         if (LoadStringW(netshell_hInstance, IDS_FORMAT_KBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
49         {
50             swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000);
51             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
52         }
53     }
54     else if (IfEntry->dwSpeed < 1000000000)
55     {
56         if (LoadStringW(netshell_hInstance, IDS_FORMAT_MBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
57         {
58             swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000000);
59             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
60         }
61     }
62     else
63     {
64         if (LoadStringW(netshell_hInstance, IDS_FORMAT_GBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
65         {
66             swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000000000);
67             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
68         }
69     }
70 
71     if (StrFormatByteSizeW(IfEntry->dwInOctets, szBuffer, sizeof(szFormat)/sizeof(WCHAR)))
72     {
73         SendDlgItemMessageW(hwndDlg, IDC_RECEIVED, WM_SETTEXT, 0, (LPARAM)szBuffer);
74     }
75 
76     if (StrFormatByteSizeW(IfEntry->dwOutOctets, szBuffer, sizeof(szFormat)/sizeof(WCHAR)))
77     {
78         SendDlgItemMessageW(hwndDlg, IDC_SEND, WM_SETTEXT, 0, (LPARAM)szBuffer);
79     }
80 
81 #if 0
82     Ticks = GetTickCount64();
83 #else
84     Ticks = GetTickCount();
85 #endif
86 
87     DurationSeconds = Ticks / 1000;
88     TimeConnected.wSecond = (DurationSeconds % 60);
89     TimeConnected.wMinute = (DurationSeconds / 60) % 60;
90     TimeConnected.wHour = (DurationSeconds / (60 * 60)) % 24;
91     TimeConnected.wDay = DurationSeconds / (60 * 60 * 24);
92 
93     if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &TimeConnected, L"HH':'mm':'ss", LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0])))
94         return;
95 
96     if (!TimeConnected.wDay)
97     {
98         SendDlgItemMessageW(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)LocBuffer);
99     }
100     else
101     {
102         if (TimeConnected.wDay == 1)
103         {
104             if (!LoadStringW(netshell_hInstance, IDS_DURATION_DAY, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0])))
105                 DayBuffer[0] = L'\0';
106         }
107         else
108         {
109             if (!LoadStringW(netshell_hInstance, IDS_DURATION_DAYS, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0])))
110                 DayBuffer[0] = L'\0';
111         }
112         swprintf(Buffer, DayBuffer, TimeConnected.wDay, LocBuffer);
113         SendDlgItemMessageW(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)Buffer);
114     }
115 
116 }
117 
118 VOID
119 UpdateLanStatus(HWND hwndDlg,  LANSTATUSUI_CONTEXT * pContext)
120 {
121     MIB_IFROW IfEntry;
122     HICON hIcon, hOldIcon = NULL;
123     NOTIFYICONDATAW nid;
124     NETCON_PROPERTIES * pProperties = NULL;
125 
126     ZeroMemory(&IfEntry, sizeof(IfEntry));
127     IfEntry.dwIndex = pContext->dwAdapterIndex;
128     if (GetIfEntry(&IfEntry) != NO_ERROR)
129     {
130         return;
131     }
132 
133     hIcon = NULL;
134     if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
135     {
136         if (pContext->dwInOctets == IfEntry.dwInOctets && pContext->dwOutOctets == IfEntry.dwOutOctets && pContext->Status  != 0)
137         {
138             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE), IMAGE_ICON, 32, 32, LR_SHARED);
139             pContext->Status = 0;
140         }
141         else if (pContext->dwInOctets != IfEntry.dwInOctets && pContext->dwOutOctets != IfEntry.dwOutOctets && pContext->Status  != 1)
142         {
143             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_TRANSREC), IMAGE_ICON, 32, 32, LR_SHARED);
144             pContext->Status = 1;
145         }
146         else if (pContext->dwInOctets != IfEntry.dwInOctets && pContext->Status  != 2)
147         {
148             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_REC), IMAGE_ICON, 32, 32, LR_SHARED);
149             pContext->Status = 2;
150         }
151         else if (pContext->dwOutOctets != IfEntry.dwOutOctets && pContext->Status  != 3)
152         {
153             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_TRANS), IMAGE_ICON, 32, 32, LR_SHARED);
154             pContext->Status = 3;
155         }
156     }
157     else if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_UNREACHABLE || IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_DISCONNECTED)
158     {
159         if (pContext->Status != 4)
160         {
161             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 32, 32, LR_SHARED);
162             pContext->Status = 4;
163         }
164     }
165     else if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_NON_OPERATIONAL)
166     {
167         if (pContext->Status != 5)
168         {
169             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 32, 32, LR_SHARED);
170             pContext->Status = 5;
171         }
172     }
173 
174     if (hwndDlg && hIcon)
175     {
176         hOldIcon = (HICON)SendDlgItemMessageW(hwndDlg, IDC_NETSTAT, STM_SETICON, (WPARAM)hIcon, 0);
177         if (hOldIcon)
178             DestroyIcon(hOldIcon);
179     }
180 
181     ZeroMemory(&nid, sizeof(nid));
182     nid.cbSize = sizeof(nid);
183     nid.uID = pContext->uID;
184     nid.hWnd = pContext->hwndStatusDlg;
185     nid.uVersion = NOTIFYICON_VERSION;
186 
187     if (pContext->pNet->GetProperties(&pProperties) == S_OK)
188     {
189         if (pProperties->dwCharacter & NCCF_SHOW_ICON)
190         {
191             if (hwndDlg)
192                 nid.hIcon = (HICON)CopyImage(hIcon, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE);
193             else
194                 nid.hIcon = hIcon;
195 
196             if (nid.hIcon)
197                 nid.uFlags |= NIF_ICON;
198 
199             nid.uFlags |= NIF_STATE;
200             nid.dwState = 0;
201             nid.dwStateMask = NIS_HIDDEN;
202 
203             if (pProperties->pszwName)
204             {
205                 if (wcslen(pProperties->pszwName) * sizeof(WCHAR) < sizeof(nid.szTip))
206                 {
207                     nid.uFlags |= NIF_TIP;
208                     wcscpy(nid.szTip, pProperties->pszwName);
209                 }
210                 else
211                 {
212                     CopyMemory(nid.szTip, pProperties->pszwName, sizeof(nid.szTip) - sizeof(WCHAR));
213                     nid.szTip[(sizeof(nid.szTip)/sizeof(WCHAR))-1] = L'\0';
214                     nid.uFlags |= NIF_TIP;
215                 }
216             }
217         }
218         else
219         {
220             nid.uFlags |= NIF_STATE;
221             nid.dwState = NIS_HIDDEN;
222             nid.dwStateMask = NIS_HIDDEN;
223 
224         }
225         NcFreeNetconProperties(pProperties);
226     }
227 
228     Shell_NotifyIconW(NIM_MODIFY, &nid);
229 
230     if (nid.uFlags & NIF_ICON)
231         DestroyIcon(nid.hIcon);
232 
233     pContext->dwInOctets = IfEntry.dwInOctets;
234     pContext->dwOutOctets = IfEntry.dwOutOctets;
235 
236     if (hwndDlg)
237         UpdateLanStatusUiDlg(hwndDlg, &IfEntry, pContext);
238 }
239 
240 
241 VOID
242 InitializeLANStatusUiDlg(HWND hwndDlg, LANSTATUSUI_CONTEXT * pContext)
243 {
244     WCHAR szBuffer[MAX_PATH] = {0};
245     NETCON_PROPERTIES * pProperties;
246 
247     if (pContext->pNet->GetProperties(&pProperties) != S_OK)
248         return;
249 
250     if (pProperties->Status == NCS_DISCONNECTED)
251         LoadStringW(netshell_hInstance, IDS_STATUS_UNREACHABLE, szBuffer, MAX_PATH);
252     else if (pProperties->Status == NCS_MEDIA_DISCONNECTED)
253         LoadStringW(netshell_hInstance, IDS_STATUS_DISCONNECTED, szBuffer, MAX_PATH);
254     else if (pProperties->Status == NCS_CONNECTING)
255         LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTING, szBuffer, MAX_PATH);
256     else if (pProperties->Status == NCS_CONNECTED)
257          LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTED, szBuffer, MAX_PATH);
258 
259     SendDlgItemMessageW(hwndDlg, IDC_STATUS, WM_SETTEXT, 0, (LPARAM)szBuffer);
260 
261     pContext->dwInOctets = 0;
262     pContext->dwOutOctets = 0;
263 
264     /* update adapter info */
265     pContext->Status = -1;
266     UpdateLanStatus(hwndDlg, pContext);
267     NcFreeNetconProperties(pProperties);
268 }
269 
270 static
271 VOID
272 InsertColumnToListView(
273     HWND hDlgCtrl,
274     UINT ResId,
275     UINT SubItem,
276     UINT Size)
277 {
278     WCHAR szBuffer[200];
279     LVCOLUMNW lc;
280 
281     if (!LoadStringW(netshell_hInstance, ResId, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
282         return;
283 
284     memset(&lc, 0, sizeof(LV_COLUMN) );
285     lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
286     lc.iSubItem   = SubItem;
287     lc.fmt = LVCFMT_FIXED_WIDTH;
288     lc.cx         = Size;
289     lc.cchTextMax = wcslen(szBuffer);
290     lc.pszText    = szBuffer;
291 
292     (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, SubItem, (LPARAM)&lc);
293 }
294 
295 static
296 VOID
297 AddIPAddressToListView(
298     HWND hDlgCtrl,
299     PIP_ADDR_STRING pAddr,
300     INT Index)
301 {
302     LVITEMW li;
303     PIP_ADDR_STRING pCur;
304     WCHAR szBuffer[100];
305     UINT SubIndex;
306 
307     ZeroMemory(&li, sizeof(LVITEMW));
308     li.mask = LVIF_TEXT;
309     li.iItem = Index;
310     pCur = pAddr;
311     SubIndex = 0;
312 
313     do
314     {
315         if (SubIndex)
316         {
317             ZeroMemory(&li, sizeof(LVITEMW));
318             li.mask = LVIF_TEXT;
319             li.iItem = Index;
320             li.iSubItem = 0;
321             li.pszText = (LPWSTR)L"";
322             li.iItem = SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
323         }
324 
325         if (MultiByteToWideChar(CP_ACP, 0, pCur->IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
326         {
327             li.pszText = szBuffer;
328             li.iSubItem = 1;
329             li.iItem = Index++;
330             SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
331         }
332         SubIndex++;
333         pCur = pCur->Next;
334     } while (pCur && pCur->IpAddress.String[0]);
335 }
336 
337 static
338 INT
339 InsertItemToListView(
340     HWND hDlgCtrl,
341     UINT ResId)
342 {
343     LVITEMW li;
344     WCHAR szBuffer[100];
345 
346     ZeroMemory(&li, sizeof(LVITEMW));
347     li.mask = LVIF_TEXT;
348     li.iItem = ListView_GetItemCount(hDlgCtrl);
349     if (LoadStringW(netshell_hInstance, ResId, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
350     {
351         li.pszText = szBuffer;
352         return (INT)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
353     }
354     return -1;
355 }
356 
357 
358 INT_PTR
359 CALLBACK
360 LANStatusUiDetailsDlg(
361     HWND hwndDlg,
362     UINT uMsg,
363     WPARAM wParam,
364     LPARAM lParam
365 )
366 {
367     LANSTATUSUI_CONTEXT * pContext;
368     LVITEMW li;
369     WCHAR szBuffer[100];
370     PIP_ADAPTER_INFO pAdapterInfo, pCurAdapter;
371     PIP_PER_ADAPTER_INFO pPerAdapter;
372     DWORD dwSize;
373     HWND hDlgCtrl;
374     RECT rect;
375 
376     switch (uMsg)
377     {
378         case WM_INITDIALOG:
379             pContext = (LANSTATUSUI_CONTEXT*)lParam;
380 
381             hDlgCtrl = GetDlgItem(hwndDlg, IDC_DETAILS);
382 
383             /* get client rect */
384             GetClientRect(hDlgCtrl, &rect);
385 
386             /* calculate column width */
387             dwSize = rect.right / 2;
388 
389             InsertColumnToListView(hDlgCtrl, IDS_PROPERTY, 0, dwSize);
390             InsertColumnToListView(hDlgCtrl, IDS_VALUE, 1, dwSize);
391 
392             dwSize = 0;
393             pCurAdapter = NULL;
394             pAdapterInfo = NULL;
395             if (GetAdaptersInfo(NULL, &dwSize) == ERROR_BUFFER_OVERFLOW)
396             {
397                 pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
398                 if (pAdapterInfo)
399                 {
400                     if (GetAdaptersInfo(pAdapterInfo, &dwSize) == NO_ERROR)
401                     {
402                         pCurAdapter = pAdapterInfo;
403                         while (pCurAdapter && pCurAdapter->Index != pContext->dwAdapterIndex)
404                             pCurAdapter = pCurAdapter->Next;
405 
406                         if (pCurAdapter->Index != pContext->dwAdapterIndex)
407                             pCurAdapter = NULL;
408                     }
409                 }
410             }
411 
412             ZeroMemory(&li, sizeof(LVITEMW));
413             li.mask = LVIF_TEXT;
414             li.iSubItem = 1;
415             li.pszText = szBuffer;
416 
417             if (pCurAdapter)
418             {
419                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_PHYSICAL_ADDRESS);
420                 if (li.iItem >= 0)
421                 {
422                     swprintf(szBuffer, L"%02x-%02x-%02x-%02x-%02x-%02x",pCurAdapter->Address[0], pCurAdapter->Address[1],
423                              pCurAdapter->Address[2], pCurAdapter->Address[3], pCurAdapter->Address[4], pCurAdapter->Address[5]);
424                     SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
425                 }
426                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_IP_ADDRESS);
427                 if (li.iItem >= 0)
428                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->IpAddressList.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
429                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
430 
431                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_SUBNET_MASK);
432                 if (li.iItem >= 0)
433                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->IpAddressList.IpMask.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
434                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
435 
436                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_DEF_GATEWAY);
437                 if (li.iItem >= 0 && pCurAdapter->GatewayList.IpAddress.String[0] != '0')
438                 {
439                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->GatewayList.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
440                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
441                 }
442 #if 0
443                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_OBTAINED);
444                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_EXPIRES);
445 #endif
446             }
447 
448             dwSize = 0;
449             if (GetPerAdapterInfo(pContext->dwAdapterIndex, NULL, &dwSize) == ERROR_BUFFER_OVERFLOW)
450             {
451                 pPerAdapter = static_cast<PIP_PER_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
452                 if (pPerAdapter)
453                 {
454                     if (GetPerAdapterInfo(pContext->dwAdapterIndex, pPerAdapter, &dwSize) == ERROR_SUCCESS)
455                     {
456                         li.iItem = InsertItemToListView(hDlgCtrl, IDS_DNS_SERVERS);
457                         if (li.iItem >= 0)
458                             AddIPAddressToListView(hDlgCtrl, &pPerAdapter->DnsServerList, li.iItem);
459                     }
460                     CoTaskMemFree(pPerAdapter);
461                 }
462             }
463 #if 0
464             if (pCurAdapter)
465             {
466                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_WINS_SERVERS);
467                 AddIPAddressToListView(hDlgCtrl, &pCurAdapter->PrimaryWinsServer, li.iItem);
468                 AddIPAddressToListView(hDlgCtrl, &pCurAdapter->SecondaryWinsServer, li.iItem+1);
469             }
470 #endif
471             CoTaskMemFree(pAdapterInfo);
472             break;
473         case WM_COMMAND:
474             if (LOWORD(wParam) == IDC_CLOSE)
475             {
476                 EndDialog(hwndDlg, FALSE);
477                 break;
478             }
479     }
480     return FALSE;
481 }
482 
483 INT_PTR
484 CALLBACK
485 LANStatusUiAdvancedDlg(
486     HWND hwndDlg,
487     UINT uMsg,
488     WPARAM wParam,
489     LPARAM lParam)
490 {
491     WCHAR szBuffer[100] = {0};
492     PROPSHEETPAGE *page;
493     LANSTATUSUI_CONTEXT * pContext;
494     DWORD dwIpAddr;
495 
496 
497     switch (uMsg)
498     {
499         case WM_INITDIALOG:
500             page = (PROPSHEETPAGE*)lParam;
501             pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
502             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
503             if (pContext->DHCPEnabled)
504                 LoadStringW(netshell_hInstance, IDS_ASSIGNED_DHCP, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
505             else
506                 LoadStringW(netshell_hInstance, IDS_ASSIGNED_MANUAL, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
507 
508             szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
509             SendDlgItemMessageW(hwndDlg, IDC_DETAILSTYPE, WM_SETTEXT, 0, (LPARAM)szBuffer);
510 
511 
512             dwIpAddr = ntohl(pContext->IpAddress);
513             swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
514                      THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
515             SendDlgItemMessageW(hwndDlg, IDC_DETAILSIP, WM_SETTEXT, 0, (LPARAM)szBuffer);
516 
517             dwIpAddr = ntohl(pContext->SubnetMask);
518             swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
519                      THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
520             SendDlgItemMessageW(hwndDlg, IDC_DETAILSSUBNET, WM_SETTEXT, 0, (LPARAM)szBuffer);
521 
522             dwIpAddr = ntohl(pContext->Gateway);
523             if (dwIpAddr)
524             {
525                 swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
526                          THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
527                 SendDlgItemMessageW(hwndDlg, IDC_DETAILSGATEWAY, WM_SETTEXT, 0, (LPARAM)szBuffer);
528             }
529             return TRUE;
530         case WM_COMMAND:
531             if (LOWORD(wParam) == IDC_DETAILS)
532             {
533                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
534                 if (pContext)
535                 {
536                     DialogBoxParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_LAN_NETSTATUSDETAILS), GetParent(hwndDlg),
537                                     LANStatusUiDetailsDlg, (LPARAM)pContext);
538                 }
539             }
540             break;
541         default:
542             break;
543     }
544     return FALSE;
545 }
546 
547 VOID
548 DisableNetworkAdapter(INetConnection * pNet, LANSTATUSUI_CONTEXT * pContext, HWND hwndDlg)
549 {
550     HRESULT hr = pNet->Disconnect();
551     if (FAILED_UNEXPECTEDLY(hr))
552         return;
553 
554     NOTIFYICONDATAW nid;
555 
556     PropSheet_PressButton(GetParent(hwndDlg), PSBTN_CANCEL);
557     ZeroMemory(&nid, sizeof(nid));
558     nid.cbSize = sizeof(nid);
559     nid.uID = pContext->uID;
560     nid.hWnd = pContext->hwndDlg;
561     nid.uFlags = NIF_STATE;
562     nid.dwState = NIS_HIDDEN;
563     nid.dwStateMask = NIS_HIDDEN;
564 
565     Shell_NotifyIconW(NIM_MODIFY, &nid);
566 }
567 
568 
569 INT_PTR
570 CALLBACK
571 LANStatusUiDlg(
572     HWND hwndDlg,
573     UINT uMsg,
574     WPARAM wParam,
575     LPARAM lParam)
576 {
577     PROPSHEETPAGE *page;
578     LANSTATUSUI_CONTEXT * pContext;
579     LPPSHNOTIFY lppsn;
580 
581     switch (uMsg)
582     {
583         case WM_INITDIALOG:
584             page = (PROPSHEETPAGE*)lParam;
585             pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
586             pContext->hwndDlg = hwndDlg;
587             InitializeLANStatusUiDlg(hwndDlg, pContext);
588             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
589             return TRUE;
590         case WM_COMMAND:
591             pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
592             if (LOWORD(wParam) == IDC_STATUS_PROPERTIES)
593             {
594                 if (pContext)
595                 {
596                     ShowNetConnectionProperties(pContext->pNet, GetParent(pContext->hwndDlg));
597                     BringWindowToTop(GetParent(pContext->hwndDlg));
598                 }
599                 break;
600             }
601             else if (LOWORD(wParam) == IDC_ENDISABLE)
602             {
603                 DisableNetworkAdapter(pContext->pNet, pContext, hwndDlg);
604                 break;
605             }
606         case WM_NOTIFY:
607             lppsn = (LPPSHNOTIFY) lParam;
608             if (lppsn->hdr.code == PSN_APPLY || lppsn->hdr.code == PSN_RESET)
609             {
610                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
611                 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
612                 pContext->hwndDlg = NULL;
613                 return TRUE;
614             }
615             break;
616     }
617     return FALSE;
618 }
619 
620 VOID
621 InitializePropertyDialog(
622     LANSTATUSUI_CONTEXT * pContext,
623     NETCON_PROPERTIES * pProperties)
624 {
625     DWORD dwSize, dwAdapterIndex, dwResult;
626     LPOLESTR pStr;
627     IP_ADAPTER_INFO *pAdapterInfo, *pCurAdapter;
628 
629     if (FAILED(StringFromCLSID((CLSID)pProperties->guidId, &pStr)))
630     {
631         return;
632     }
633 
634     /* get the IfTable */
635     dwSize = 0;
636     dwResult = GetAdaptersInfo(NULL, &dwSize);
637     if (dwResult!= ERROR_BUFFER_OVERFLOW)
638     {
639         CoTaskMemFree(pStr);
640         return;
641     }
642 
643     pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
644     if (!pAdapterInfo)
645     {
646         CoTaskMemFree(pAdapterInfo);
647         CoTaskMemFree(pStr);
648         return;
649     }
650 
651     if (GetAdaptersInfo(pAdapterInfo, &dwSize) != NO_ERROR)
652     {
653         CoTaskMemFree(pAdapterInfo);
654         CoTaskMemFree(pStr);
655         return;
656     }
657 
658     if (!GetAdapterIndexFromNetCfgInstanceId(pAdapterInfo, pStr, &dwAdapterIndex))
659     {
660         CoTaskMemFree(pAdapterInfo);
661         CoTaskMemFree(pStr);
662         return;
663     }
664 
665     pCurAdapter = pAdapterInfo;
666     while (pCurAdapter->Index != dwAdapterIndex)
667         pCurAdapter = pCurAdapter->Next;
668 
669 
670     pContext->IpAddress = inet_addr(pCurAdapter->IpAddressList.IpAddress.String);
671     pContext->SubnetMask = inet_addr(pCurAdapter->IpAddressList.IpMask.String);
672     pContext->Gateway = inet_addr(pCurAdapter->GatewayList.IpAddress.String);
673     pContext->DHCPEnabled = pCurAdapter->DhcpEnabled;
674     CoTaskMemFree(pStr);
675     CoTaskMemFree(pAdapterInfo);
676     pContext->dwAdapterIndex = dwAdapterIndex;
677 }
678 
679 static int CALLBACK
680 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
681 {
682     // NOTE: This callback is needed to set large icon correctly.
683     HICON hIcon;
684     switch (uMsg)
685     {
686         case PSCB_INITIALIZED:
687         {
688             hIcon = LoadIconW(netshell_hInstance, MAKEINTRESOURCEW(IDI_NET_IDLE));
689             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
690             break;
691         }
692     }
693     return 0;
694 }
695 
696 VOID
697 ShowStatusPropertyDialog(
698     LANSTATUSUI_CONTEXT *pContext,
699     HWND hwndDlg)
700 {
701     HPROPSHEETPAGE hppages[2];
702     PROPSHEETHEADERW pinfo;
703     NETCON_PROPERTIES * pProperties = NULL;
704 
705     ZeroMemory(&pinfo, sizeof(PROPSHEETHEADERW));
706     ZeroMemory(hppages, sizeof(hppages));
707     pinfo.dwSize = sizeof(PROPSHEETHEADERW);
708     pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE | PSH_NOAPPLYNOW |
709                     PSH_USEICONID | PSH_USECALLBACK;
710     pinfo.phpage = hppages;
711     pinfo.hwndParent = hwndDlg;
712     pinfo.hInstance = netshell_hInstance;
713     pinfo.pszIcon = MAKEINTRESOURCEW(IDI_NET_IDLE);
714     pinfo.pfnCallback = PropSheetProc;
715 
716     if (pContext->pNet->GetProperties(&pProperties) == S_OK)
717     {
718         if (pProperties->pszwName)
719         {
720             pinfo.pszCaption = pProperties->pszwName;
721             pinfo.dwFlags |= PSH_PROPTITLE;
722         }
723         InitializePropertyDialog(pContext, pProperties);
724         if (pProperties->MediaType == NCM_LAN && pProperties->Status == NCS_CONNECTED)
725         {
726             hppages[0] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUS), LANStatusUiDlg, (LPARAM)pContext, NULL);
727             if (hppages[0])
728                pinfo.nPages++;
729 
730             hppages[pinfo.nPages] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUSADVANCED), LANStatusUiAdvancedDlg, (LPARAM)pContext, NULL);
731             if (hppages[pinfo.nPages])
732                pinfo.nPages++;
733 
734             if (pinfo.nPages)
735             {
736                 PropertySheetW(&pinfo);
737             }
738         }
739         else if (pProperties->Status == NCS_MEDIA_DISCONNECTED || pProperties->Status == NCS_DISCONNECTED ||
740                  pProperties->Status == NCS_HARDWARE_DISABLED)
741         {
742             ShowNetConnectionProperties(pContext->pNet, pContext->hwndDlg);
743         }
744 
745         NcFreeNetconProperties(pProperties);
746     }
747 }
748 
749 INT_PTR
750 CALLBACK
751 LANStatusDlg(
752     HWND hwndDlg,
753     UINT uMsg,
754     WPARAM wParam,
755     LPARAM lParam)
756 {
757     LANSTATUSUI_CONTEXT * pContext;
758 
759     switch (uMsg)
760     {
761         case WM_INITDIALOG:
762             pContext = (LANSTATUSUI_CONTEXT *)lParam;
763             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
764             pContext->nIDEvent = SetTimer(hwndDlg, 0xFABC, 1000, NULL);
765             return TRUE;
766         case WM_TIMER:
767             pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
768             if (wParam == (WPARAM)pContext->nIDEvent)
769             {
770                 UpdateLanStatus(pContext->hwndDlg, pContext);
771             }
772             break;
773         case WM_SHOWSTATUSDLG:
774             if (LOWORD(lParam) == WM_LBUTTONDOWN)
775             {
776                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
777                 if (!pContext)
778                     break;
779 
780                 if (pContext->hwndDlg)
781                 {
782                     ShowWindow(GetParent(pContext->hwndDlg), SW_SHOW);
783                     BringWindowToTop(GetParent(pContext->hwndDlg));
784                 }
785                 else
786                 {
787                     ShowStatusPropertyDialog(pContext, hwndDlg);
788                 }
789                 break;
790             }
791             break;
792     }
793     return FALSE;
794 }
795 
796 HRESULT
797 CLanStatus::InitializeNetTaskbarNotifications()
798 {
799     NOTIFYICONDATAW nid;
800     HWND hwndDlg;
801     CComPtr<INetConnectionManager> pNetConMan;
802     CComPtr<IEnumNetConnection> pEnumCon;
803     CComPtr<INetConnection> pNetCon;
804     NETCON_PROPERTIES* pProps;
805     HRESULT hr;
806     ULONG Count;
807     ULONG Index;
808     NOTIFICATION_ITEM * pItem, *pLast = NULL;
809     LANSTATUSUI_CONTEXT * pContext;
810 
811     TRACE("InitializeNetTaskbarNotifications\n");
812 
813     if (m_pHead)
814     {
815        pItem = m_pHead;
816        while (pItem)
817        {
818            hr = pItem->pNet->GetProperties(&pProps);
819            if (SUCCEEDED(hr))
820            {
821                 ZeroMemory(&nid, sizeof(nid));
822                 nid.cbSize = sizeof(nid);
823                 nid.uID = pItem->uID;
824                 nid.hWnd = pItem->hwndDlg;
825                 nid.uFlags = NIF_STATE;
826                 if (pProps->dwCharacter & NCCF_SHOW_ICON)
827                     nid.dwState = 0;
828                 else
829                     nid.dwState = NIS_HIDDEN;
830 
831                 nid.dwStateMask = NIS_HIDDEN;
832                 Shell_NotifyIconW(NIM_MODIFY, &nid);
833                 NcFreeNetconProperties(pProps);
834            }
835            pItem = pItem->pNext;
836        }
837        return S_OK;
838     }
839     /* get an instance to of IConnectionManager */
840     hr = CNetConnectionManager_CreateInstance(IID_PPV_ARG(INetConnectionManager, &pNetConMan));
841     if (FAILED_UNEXPECTEDLY(hr))
842         return hr;
843 
844     hr = pNetConMan->EnumConnections(NCME_DEFAULT, &pEnumCon);
845     if (FAILED_UNEXPECTEDLY(hr))
846         return hr;
847 
848     Index = 1;
849     while (TRUE)
850     {
851         hr = pEnumCon->Next(1, &pNetCon, &Count);
852         if (hr != S_OK)
853             break;
854 
855         TRACE("new connection\n");
856         pItem = static_cast<NOTIFICATION_ITEM*>(CoTaskMemAlloc(sizeof(NOTIFICATION_ITEM)));
857         if (!pItem)
858             break;
859 
860         pContext = static_cast<LANSTATUSUI_CONTEXT*>(CoTaskMemAlloc(sizeof(LANSTATUSUI_CONTEXT)));
861         if (!pContext)
862         {
863             CoTaskMemFree(pItem);
864             break;
865         }
866 
867         ZeroMemory(pContext, sizeof(LANSTATUSUI_CONTEXT));
868         pContext->uID = Index;
869         pContext->pNet = pNetCon;
870         pItem->uID = Index;
871         pItem->pNext = NULL;
872         pItem->pNet = pNetCon;
873         pNetCon->AddRef();
874         hwndDlg = CreateDialogParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_STATUS), NULL, LANStatusDlg, (LPARAM)pContext);
875         if (!hwndDlg)
876         {
877             ERR("CreateDialogParamW failed\n");
878             continue;
879         }
880 
881         ZeroMemory(&nid, sizeof(nid));
882         nid.cbSize = sizeof(nid);
883         nid.uID = Index++;
884         nid.uFlags = NIF_MESSAGE;
885         nid.uVersion = NOTIFYICON_VERSION;
886         nid.uCallbackMessage = WM_SHOWSTATUSDLG;
887         nid.hWnd = hwndDlg;
888 
889         hr = pNetCon->GetProperties(&pProps);
890         if (SUCCEEDED(hr))
891         {
892             CopyMemory(&pItem->guidItem, &pProps->guidId, sizeof(GUID));
893             if (!(pProps->dwCharacter & NCCF_SHOW_ICON))
894             {
895                 nid.dwState = NIS_HIDDEN;
896                 nid.dwStateMask = NIS_HIDDEN;
897                 nid.uFlags |= NIF_STATE;
898             }
899             if (pProps->Status == NCS_MEDIA_DISCONNECTED || pProps->Status == NCS_DISCONNECTED || pProps->Status == NCS_HARDWARE_DISABLED)
900                 nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF));
901             else if (pProps->Status == NCS_CONNECTED)
902                 nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE));
903 
904             if (nid.hIcon)
905                 nid.uFlags |= NIF_ICON;
906 
907             wcscpy(nid.szTip, pProps->pszwName);
908             nid.uFlags |= NIF_TIP;
909         }
910         pContext->hwndStatusDlg = hwndDlg;
911         pItem->hwndDlg = hwndDlg;
912 
913         if (Shell_NotifyIconW(NIM_ADD, &nid))
914         {
915             if (pLast)
916                 pLast->pNext = pItem;
917             else
918                 m_pHead = pItem;
919 
920             pLast = pItem;
921             Index++;
922         }
923         else
924         {
925             ERR("Shell_NotifyIconW failed\n");
926             CoTaskMemFree(pItem);
927         }
928 
929         if (nid.uFlags & NIF_ICON)
930             DestroyIcon(nid.hIcon);
931     }
932 
933     m_lpNetMan = pNetConMan;
934     return S_OK;
935 }
936 
937 HRESULT
938 CLanStatus::ShowStatusDialogByCLSID(const GUID *pguidCmdGroup)
939 {
940     NOTIFICATION_ITEM *pItem;
941 
942     pItem = m_pHead;
943     while (pItem)
944     {
945         if (IsEqualGUID(pItem->guidItem, *pguidCmdGroup))
946         {
947             SendMessageW(pItem->hwndDlg, WM_SHOWSTATUSDLG, 0, WM_LBUTTONDOWN);
948             return S_OK;
949         }
950         pItem = pItem->pNext;
951     }
952 
953     ERR("not found\n");
954     return E_FAIL;
955 }
956 
957 HRESULT
958 WINAPI
959 CLanStatus::QueryStatus(
960     const GUID *pguidCmdGroup,
961     ULONG cCmds,
962     OLECMD *prgCmds,
963     OLECMDTEXT *pCmdText)
964 {
965     MessageBoxW(NULL, pCmdText->rgwz, L"IOleCommandTarget_fnQueryStatus", MB_OK);
966     return E_NOTIMPL;
967 }
968 
969 HRESULT
970 WINAPI
971 CLanStatus::Exec(
972     const GUID *pguidCmdGroup,
973     DWORD nCmdID,
974     DWORD nCmdexecopt,
975     VARIANT *pvaIn,
976     VARIANT *pvaOut)
977 {
978     if (pguidCmdGroup)
979     {
980         if (IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
981         {
982             return InitializeNetTaskbarNotifications();
983         }
984         else
985         {
986             /* invoke status dialog */
987             return ShowStatusDialogByCLSID(pguidCmdGroup);
988         }
989     }
990     return S_OK;
991 }
992