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 
443                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_DHCP_SERVER);
444                 if (li.iItem >= 0 && pCurAdapter->DhcpServer.IpAddress.String[0] != '0')
445                 {
446                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->DhcpServer.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
447                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
448                 }
449 
450                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_OBTAINED);
451                 if (li.iItem >= 0 && pCurAdapter->LeaseObtained != NULL)
452                 {
453                     struct tm *leaseOptained;
454 
455                     leaseOptained = localtime(&pCurAdapter->LeaseObtained);
456 
457                     if (wcsftime(szBuffer, 100, L"%m/%d/%Y %H:%M:%S %p", leaseOptained) != 0)
458                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
459                 }
460 
461                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_EXPIRES);
462                 if (li.iItem >= 0 && pCurAdapter->LeaseExpires != NULL)
463                 {
464                     struct tm *leaseExpire;
465 
466                     leaseExpire = localtime(&pCurAdapter->LeaseExpires);
467 
468                     if (wcsftime(szBuffer, 100, L"%m/%d/%Y %H:%M:%S %p", leaseExpire) != 0)
469                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
470                 }
471             }
472 
473             dwSize = 0;
474             li.iItem = InsertItemToListView(hDlgCtrl, IDS_DNS_SERVERS);
475             if (GetPerAdapterInfo(pContext->dwAdapterIndex, NULL, &dwSize) == ERROR_BUFFER_OVERFLOW)
476             {
477                 pPerAdapter = static_cast<PIP_PER_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
478                 if (pPerAdapter)
479                 {
480                     if (GetPerAdapterInfo(pContext->dwAdapterIndex, pPerAdapter, &dwSize) == ERROR_SUCCESS)
481                     {
482                         li.iItem = InsertItemToListView(hDlgCtrl, IDS_DNS_SERVERS);
483                         if (li.iItem >= 0)
484                             AddIPAddressToListView(hDlgCtrl, &pPerAdapter->DnsServerList, li.iItem);
485                     }
486                     CoTaskMemFree(pPerAdapter);
487                 }
488             }
489 
490             if (pCurAdapter)
491             {
492                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_WINS_SERVERS);
493                 if (pCurAdapter->HaveWins)
494                 {
495                     AddIPAddressToListView(hDlgCtrl, &pCurAdapter->PrimaryWinsServer, li.iItem);
496                     AddIPAddressToListView(hDlgCtrl, &pCurAdapter->SecondaryWinsServer, li.iItem+1);
497                 }
498             }
499 
500             CoTaskMemFree(pAdapterInfo);
501             break;
502 
503         case WM_COMMAND:
504             if (LOWORD(wParam) == IDC_CLOSE)
505             {
506                 EndDialog(hwndDlg, FALSE);
507                 break;
508             }
509     }
510 
511     return FALSE;
512 }
513 
514 INT_PTR
515 CALLBACK
516 LANStatusUiAdvancedDlg(
517     HWND hwndDlg,
518     UINT uMsg,
519     WPARAM wParam,
520     LPARAM lParam)
521 {
522     WCHAR szBuffer[100] = {0};
523     PROPSHEETPAGE *page;
524     LANSTATUSUI_CONTEXT * pContext;
525     DWORD dwIpAddr;
526 
527 
528     switch (uMsg)
529     {
530         case WM_INITDIALOG:
531             page = (PROPSHEETPAGE*)lParam;
532             pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
533             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
534             if (pContext->DHCPEnabled)
535                 LoadStringW(netshell_hInstance, IDS_ASSIGNED_DHCP, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
536             else
537                 LoadStringW(netshell_hInstance, IDS_ASSIGNED_MANUAL, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
538 
539             szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
540             SendDlgItemMessageW(hwndDlg, IDC_DETAILSTYPE, WM_SETTEXT, 0, (LPARAM)szBuffer);
541 
542 
543             dwIpAddr = ntohl(pContext->IpAddress);
544             swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
545                      THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
546             SendDlgItemMessageW(hwndDlg, IDC_DETAILSIP, WM_SETTEXT, 0, (LPARAM)szBuffer);
547 
548             dwIpAddr = ntohl(pContext->SubnetMask);
549             swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
550                      THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
551             SendDlgItemMessageW(hwndDlg, IDC_DETAILSSUBNET, WM_SETTEXT, 0, (LPARAM)szBuffer);
552 
553             dwIpAddr = ntohl(pContext->Gateway);
554             if (dwIpAddr)
555             {
556                 swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
557                          THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
558                 SendDlgItemMessageW(hwndDlg, IDC_DETAILSGATEWAY, WM_SETTEXT, 0, (LPARAM)szBuffer);
559             }
560             return TRUE;
561         case WM_COMMAND:
562             if (LOWORD(wParam) == IDC_DETAILS)
563             {
564                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
565                 if (pContext)
566                 {
567                     DialogBoxParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_LAN_NETSTATUSDETAILS), GetParent(hwndDlg),
568                                     LANStatusUiDetailsDlg, (LPARAM)pContext);
569                 }
570             }
571             break;
572         default:
573             break;
574     }
575     return FALSE;
576 }
577 
578 VOID
579 DisableNetworkAdapter(INetConnection * pNet, LANSTATUSUI_CONTEXT * pContext, HWND hwndDlg)
580 {
581     HRESULT hr = pNet->Disconnect();
582     if (FAILED_UNEXPECTEDLY(hr))
583         return;
584 
585     NOTIFYICONDATAW nid;
586 
587     PropSheet_PressButton(GetParent(hwndDlg), PSBTN_CANCEL);
588     ZeroMemory(&nid, sizeof(nid));
589     nid.cbSize = sizeof(nid);
590     nid.uID = pContext->uID;
591     nid.hWnd = pContext->hwndDlg;
592     nid.uFlags = NIF_STATE;
593     nid.dwState = NIS_HIDDEN;
594     nid.dwStateMask = NIS_HIDDEN;
595 
596     Shell_NotifyIconW(NIM_MODIFY, &nid);
597 }
598 
599 
600 INT_PTR
601 CALLBACK
602 LANStatusUiDlg(
603     HWND hwndDlg,
604     UINT uMsg,
605     WPARAM wParam,
606     LPARAM lParam)
607 {
608     PROPSHEETPAGE *page;
609     LANSTATUSUI_CONTEXT * pContext;
610     LPPSHNOTIFY lppsn;
611 
612     switch (uMsg)
613     {
614         case WM_INITDIALOG:
615             page = (PROPSHEETPAGE*)lParam;
616             pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
617             pContext->hwndDlg = hwndDlg;
618             InitializeLANStatusUiDlg(hwndDlg, pContext);
619             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
620             return TRUE;
621         case WM_COMMAND:
622             pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
623             if (LOWORD(wParam) == IDC_STATUS_PROPERTIES)
624             {
625                 if (pContext)
626                 {
627                     ShowNetConnectionProperties(pContext->pNet, GetParent(pContext->hwndDlg));
628                     BringWindowToTop(GetParent(pContext->hwndDlg));
629                 }
630                 break;
631             }
632             else if (LOWORD(wParam) == IDC_ENDISABLE)
633             {
634                 DisableNetworkAdapter(pContext->pNet, pContext, hwndDlg);
635                 break;
636             }
637         case WM_NOTIFY:
638             lppsn = (LPPSHNOTIFY) lParam;
639             if (lppsn->hdr.code == PSN_APPLY || lppsn->hdr.code == PSN_RESET)
640             {
641                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
642                 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
643                 pContext->hwndDlg = NULL;
644                 return TRUE;
645             }
646             break;
647     }
648     return FALSE;
649 }
650 
651 VOID
652 InitializePropertyDialog(
653     LANSTATUSUI_CONTEXT * pContext,
654     NETCON_PROPERTIES * pProperties)
655 {
656     DWORD dwSize, dwAdapterIndex, dwResult;
657     LPOLESTR pStr;
658     IP_ADAPTER_INFO *pAdapterInfo, *pCurAdapter;
659 
660     if (FAILED(StringFromCLSID((CLSID)pProperties->guidId, &pStr)))
661     {
662         return;
663     }
664 
665     /* get the IfTable */
666     dwSize = 0;
667     dwResult = GetAdaptersInfo(NULL, &dwSize);
668     if (dwResult!= ERROR_BUFFER_OVERFLOW)
669     {
670         CoTaskMemFree(pStr);
671         return;
672     }
673 
674     pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
675     if (!pAdapterInfo)
676     {
677         CoTaskMemFree(pAdapterInfo);
678         CoTaskMemFree(pStr);
679         return;
680     }
681 
682     if (GetAdaptersInfo(pAdapterInfo, &dwSize) != NO_ERROR)
683     {
684         CoTaskMemFree(pAdapterInfo);
685         CoTaskMemFree(pStr);
686         return;
687     }
688 
689     if (!GetAdapterIndexFromNetCfgInstanceId(pAdapterInfo, pStr, &dwAdapterIndex))
690     {
691         CoTaskMemFree(pAdapterInfo);
692         CoTaskMemFree(pStr);
693         return;
694     }
695 
696     pCurAdapter = pAdapterInfo;
697     while (pCurAdapter->Index != dwAdapterIndex)
698         pCurAdapter = pCurAdapter->Next;
699 
700 
701     pContext->IpAddress = inet_addr(pCurAdapter->IpAddressList.IpAddress.String);
702     pContext->SubnetMask = inet_addr(pCurAdapter->IpAddressList.IpMask.String);
703     pContext->Gateway = inet_addr(pCurAdapter->GatewayList.IpAddress.String);
704     pContext->DHCPEnabled = pCurAdapter->DhcpEnabled;
705     CoTaskMemFree(pStr);
706     CoTaskMemFree(pAdapterInfo);
707     pContext->dwAdapterIndex = dwAdapterIndex;
708 }
709 
710 static int CALLBACK
711 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
712 {
713     // NOTE: This callback is needed to set large icon correctly.
714     HICON hIcon;
715     switch (uMsg)
716     {
717         case PSCB_INITIALIZED:
718         {
719             hIcon = LoadIconW(netshell_hInstance, MAKEINTRESOURCEW(IDI_NET_IDLE));
720             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
721             break;
722         }
723     }
724     return 0;
725 }
726 
727 VOID
728 ShowStatusPropertyDialog(
729     LANSTATUSUI_CONTEXT *pContext,
730     HWND hwndDlg)
731 {
732     HPROPSHEETPAGE hppages[2];
733     PROPSHEETHEADERW pinfo;
734     NETCON_PROPERTIES * pProperties = NULL;
735 
736     ZeroMemory(&pinfo, sizeof(PROPSHEETHEADERW));
737     ZeroMemory(hppages, sizeof(hppages));
738     pinfo.dwSize = sizeof(PROPSHEETHEADERW);
739     pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE | PSH_NOAPPLYNOW |
740                     PSH_USEICONID | PSH_USECALLBACK;
741     pinfo.phpage = hppages;
742     pinfo.hwndParent = hwndDlg;
743     pinfo.hInstance = netshell_hInstance;
744     pinfo.pszIcon = MAKEINTRESOURCEW(IDI_NET_IDLE);
745     pinfo.pfnCallback = PropSheetProc;
746 
747     if (pContext->pNet->GetProperties(&pProperties) == S_OK)
748     {
749         if (pProperties->pszwName)
750         {
751             pinfo.pszCaption = pProperties->pszwName;
752             pinfo.dwFlags |= PSH_PROPTITLE;
753         }
754         InitializePropertyDialog(pContext, pProperties);
755         if (pProperties->MediaType == NCM_LAN && pProperties->Status == NCS_CONNECTED)
756         {
757             hppages[0] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUS), LANStatusUiDlg, (LPARAM)pContext, NULL);
758             if (hppages[0])
759                pinfo.nPages++;
760 
761             hppages[pinfo.nPages] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUSADVANCED), LANStatusUiAdvancedDlg, (LPARAM)pContext, NULL);
762             if (hppages[pinfo.nPages])
763                pinfo.nPages++;
764 
765             if (pinfo.nPages)
766             {
767                 PropertySheetW(&pinfo);
768             }
769         }
770         else if (pProperties->Status == NCS_MEDIA_DISCONNECTED || pProperties->Status == NCS_DISCONNECTED ||
771                  pProperties->Status == NCS_HARDWARE_DISABLED)
772         {
773             ShowNetConnectionProperties(pContext->pNet, pContext->hwndDlg);
774         }
775 
776         NcFreeNetconProperties(pProperties);
777     }
778 }
779 
780 INT_PTR
781 CALLBACK
782 LANStatusDlg(
783     HWND hwndDlg,
784     UINT uMsg,
785     WPARAM wParam,
786     LPARAM lParam)
787 {
788     LANSTATUSUI_CONTEXT * pContext;
789 
790     switch (uMsg)
791     {
792         case WM_INITDIALOG:
793             pContext = (LANSTATUSUI_CONTEXT *)lParam;
794             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
795             pContext->nIDEvent = SetTimer(hwndDlg, 0xFABC, 1000, NULL);
796             return TRUE;
797         case WM_TIMER:
798             pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
799             if (wParam == (WPARAM)pContext->nIDEvent)
800             {
801                 UpdateLanStatus(pContext->hwndDlg, pContext);
802             }
803             break;
804         case WM_SHOWSTATUSDLG:
805             if (LOWORD(lParam) == WM_LBUTTONDOWN)
806             {
807                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
808                 if (!pContext)
809                     break;
810 
811                 if (pContext->hwndDlg)
812                 {
813                     ShowWindow(GetParent(pContext->hwndDlg), SW_SHOW);
814                     BringWindowToTop(GetParent(pContext->hwndDlg));
815                 }
816                 else
817                 {
818                     ShowStatusPropertyDialog(pContext, hwndDlg);
819                 }
820                 break;
821             }
822             break;
823     }
824     return FALSE;
825 }
826 
827 HRESULT
828 CLanStatus::InitializeNetTaskbarNotifications()
829 {
830     NOTIFYICONDATAW nid;
831     HWND hwndDlg;
832     CComPtr<INetConnectionManager> pNetConMan;
833     CComPtr<IEnumNetConnection> pEnumCon;
834     CComPtr<INetConnection> pNetCon;
835     NETCON_PROPERTIES* pProps;
836     HRESULT hr;
837     ULONG Count;
838     ULONG Index;
839     NOTIFICATION_ITEM * pItem, *pLast = NULL;
840     LANSTATUSUI_CONTEXT * pContext;
841 
842     TRACE("InitializeNetTaskbarNotifications\n");
843 
844     if (m_pHead)
845     {
846        pItem = m_pHead;
847        while (pItem)
848        {
849            hr = pItem->pNet->GetProperties(&pProps);
850            if (SUCCEEDED(hr))
851            {
852                 ZeroMemory(&nid, sizeof(nid));
853                 nid.cbSize = sizeof(nid);
854                 nid.uID = pItem->uID;
855                 nid.hWnd = pItem->hwndDlg;
856                 nid.uFlags = NIF_STATE;
857                 if (pProps->dwCharacter & NCCF_SHOW_ICON)
858                     nid.dwState = 0;
859                 else
860                     nid.dwState = NIS_HIDDEN;
861 
862                 nid.dwStateMask = NIS_HIDDEN;
863                 Shell_NotifyIconW(NIM_MODIFY, &nid);
864                 NcFreeNetconProperties(pProps);
865            }
866            pItem = pItem->pNext;
867        }
868        return S_OK;
869     }
870     /* get an instance to of IConnectionManager */
871     hr = CNetConnectionManager_CreateInstance(IID_PPV_ARG(INetConnectionManager, &pNetConMan));
872     if (FAILED_UNEXPECTEDLY(hr))
873         return hr;
874 
875     hr = pNetConMan->EnumConnections(NCME_DEFAULT, &pEnumCon);
876     if (FAILED_UNEXPECTEDLY(hr))
877         return hr;
878 
879     Index = 1;
880     while (TRUE)
881     {
882         hr = pEnumCon->Next(1, &pNetCon, &Count);
883         if (hr != S_OK)
884             break;
885 
886         TRACE("new connection\n");
887         pItem = static_cast<NOTIFICATION_ITEM*>(CoTaskMemAlloc(sizeof(NOTIFICATION_ITEM)));
888         if (!pItem)
889             break;
890 
891         pContext = static_cast<LANSTATUSUI_CONTEXT*>(CoTaskMemAlloc(sizeof(LANSTATUSUI_CONTEXT)));
892         if (!pContext)
893         {
894             CoTaskMemFree(pItem);
895             break;
896         }
897 
898         ZeroMemory(pContext, sizeof(LANSTATUSUI_CONTEXT));
899         pContext->uID = Index;
900         pContext->pNet = pNetCon;
901         pItem->uID = Index;
902         pItem->pNext = NULL;
903         pItem->pNet = pNetCon;
904         pNetCon->AddRef();
905         hwndDlg = CreateDialogParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_STATUS), NULL, LANStatusDlg, (LPARAM)pContext);
906         if (!hwndDlg)
907         {
908             ERR("CreateDialogParamW failed\n");
909             continue;
910         }
911 
912         ZeroMemory(&nid, sizeof(nid));
913         nid.cbSize = sizeof(nid);
914         nid.uID = Index++;
915         nid.uFlags = NIF_MESSAGE;
916         nid.uVersion = NOTIFYICON_VERSION;
917         nid.uCallbackMessage = WM_SHOWSTATUSDLG;
918         nid.hWnd = hwndDlg;
919 
920         hr = pNetCon->GetProperties(&pProps);
921         if (SUCCEEDED(hr))
922         {
923             CopyMemory(&pItem->guidItem, &pProps->guidId, sizeof(GUID));
924             if (!(pProps->dwCharacter & NCCF_SHOW_ICON))
925             {
926                 nid.dwState = NIS_HIDDEN;
927                 nid.dwStateMask = NIS_HIDDEN;
928                 nid.uFlags |= NIF_STATE;
929             }
930             if (pProps->Status == NCS_MEDIA_DISCONNECTED || pProps->Status == NCS_DISCONNECTED || pProps->Status == NCS_HARDWARE_DISABLED)
931                 nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF));
932             else if (pProps->Status == NCS_CONNECTED)
933                 nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE));
934 
935             if (nid.hIcon)
936                 nid.uFlags |= NIF_ICON;
937 
938             wcscpy(nid.szTip, pProps->pszwName);
939             nid.uFlags |= NIF_TIP;
940         }
941         pContext->hwndStatusDlg = hwndDlg;
942         pItem->hwndDlg = hwndDlg;
943 
944         if (Shell_NotifyIconW(NIM_ADD, &nid))
945         {
946             if (pLast)
947                 pLast->pNext = pItem;
948             else
949                 m_pHead = pItem;
950 
951             pLast = pItem;
952             Index++;
953         }
954         else
955         {
956             ERR("Shell_NotifyIconW failed\n");
957             CoTaskMemFree(pItem);
958         }
959 
960         if (nid.uFlags & NIF_ICON)
961             DestroyIcon(nid.hIcon);
962     }
963 
964     m_lpNetMan = pNetConMan;
965     return S_OK;
966 }
967 
968 HRESULT
969 CLanStatus::ShowStatusDialogByCLSID(const GUID *pguidCmdGroup)
970 {
971     NOTIFICATION_ITEM *pItem;
972 
973     pItem = m_pHead;
974     while (pItem)
975     {
976         if (IsEqualGUID(pItem->guidItem, *pguidCmdGroup))
977         {
978             SendMessageW(pItem->hwndDlg, WM_SHOWSTATUSDLG, 0, WM_LBUTTONDOWN);
979             return S_OK;
980         }
981         pItem = pItem->pNext;
982     }
983 
984     ERR("not found\n");
985     return E_FAIL;
986 }
987 
988 HRESULT
989 WINAPI
990 CLanStatus::QueryStatus(
991     const GUID *pguidCmdGroup,
992     ULONG cCmds,
993     OLECMD *prgCmds,
994     OLECMDTEXT *pCmdText)
995 {
996     MessageBoxW(NULL, pCmdText->rgwz, L"IOleCommandTarget_fnQueryStatus", MB_OK);
997     return E_NOTIMPL;
998 }
999 
1000 HRESULT
1001 WINAPI
1002 CLanStatus::Exec(
1003     const GUID *pguidCmdGroup,
1004     DWORD nCmdID,
1005     DWORD nCmdexecopt,
1006     VARIANT *pvaIn,
1007     VARIANT *pvaOut)
1008 {
1009     if (pguidCmdGroup)
1010     {
1011         if (IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
1012         {
1013             return InitializeNetTaskbarNotifications();
1014         }
1015         else
1016         {
1017             /* invoke status dialog */
1018             return ShowStatusDialogByCLSID(pguidCmdGroup);
1019         }
1020     }
1021     return S_OK;
1022 }
1023