1 /*
2  * PROJECT:     ReactOS Shell
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     CNetConnectionPropertyUi: Network connection configuration dialog
5  * COPYRIGHT:   Copyright 2008 Johannes Anderwald (johannes.anderwald@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 CNetConnectionPropertyUi::CNetConnectionPropertyUi() :
11     m_pProperties(NULL)
12 {
13 }
14 
15 CNetConnectionPropertyUi::~CNetConnectionPropertyUi()
16 {
17     if (m_pNCfg)
18         m_pNCfg->Uninitialize();
19 
20     if (m_pProperties)
21         NcFreeNetconProperties(m_pProperties);
22 }
23 
24 VOID
25 AddItemToListView(HWND hDlgCtrl, PNET_ITEM pItem, LPWSTR szName, BOOL bChecked)
26 {
27     LVITEMW lvItem;
28 
29     ZeroMemory(&lvItem, sizeof(lvItem));
30     lvItem.mask  = LVIF_TEXT | LVIF_PARAM;
31     lvItem.pszText = szName;
32     lvItem.lParam = (LPARAM)pItem;
33     lvItem.iItem = ListView_GetItemCount(hDlgCtrl);
34     lvItem.iItem = SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
35     ListView_SetCheckState(hDlgCtrl, lvItem.iItem, bChecked);
36 }
37 
38 BOOL
39 CNetConnectionPropertyUi::GetINetCfgComponent(INetCfg *pNCfg, INetCfgComponent ** pOut)
40 {
41     LPWSTR pName;
42     HRESULT hr;
43     ULONG Fetched;
44     CComPtr<IEnumNetCfgComponent> pEnumCfg;
45 
46     hr = pNCfg->EnumComponents(&GUID_DEVCLASS_NET, &pEnumCfg);
47     if (FAILED_UNEXPECTEDLY(hr))
48         return FALSE;
49 
50     while (TRUE)
51     {
52         CComPtr<INetCfgComponent> pNCg;
53         hr = pEnumCfg->Next(1, &pNCg, &Fetched);
54         if (hr != S_OK)
55             break;
56 
57         hr = pNCg->GetDisplayName(&pName);
58         if (SUCCEEDED(hr))
59         {
60             if (!_wcsicmp(pName, m_pProperties->pszwDeviceName))
61             {
62                 *pOut = pNCg.Detach();
63                 return TRUE;
64             }
65             CoTaskMemFree(pName);
66         }
67     }
68     return FALSE;
69 }
70 
71 VOID
72 CNetConnectionPropertyUi::EnumComponents(HWND hDlgCtrl, INetCfg *pNCfg, const GUID *CompGuid, UINT Type)
73 {
74     HRESULT hr;
75     CComPtr<IEnumNetCfgComponent> pENetCfg;
76     ULONG Num;
77     DWORD dwCharacteristics;
78     LPOLESTR pDisplayName, pHelpText;
79     PNET_ITEM pItem;
80     BOOL bChecked;
81 
82     hr = pNCfg->EnumComponents(CompGuid, &pENetCfg);
83     if (FAILED_UNEXPECTEDLY(hr))
84         return;
85 
86     while (TRUE)
87     {
88         CComPtr<INetCfgComponent> pNCfgComp;
89         CComPtr<INetCfgComponentBindings> pCompBind;
90         CComPtr<INetCfgComponent> pAdapterCfgComp;
91 
92         hr = pENetCfg->Next(1, &pNCfgComp, &Num);
93         if (hr != S_OK)
94             break;
95 
96         hr = pNCfgComp->GetCharacteristics(&dwCharacteristics);
97         if (SUCCEEDED(hr) && (dwCharacteristics & NCF_HIDDEN))
98             continue;
99 
100         pDisplayName = NULL;
101         pHelpText = NULL;
102         hr = pNCfgComp->GetDisplayName(&pDisplayName);
103         hr = pNCfgComp->GetHelpText(&pHelpText);
104         bChecked = TRUE; //ReactOS hack
105         hr = pNCfgComp->QueryInterface(IID_PPV_ARG(INetCfgComponentBindings, &pCompBind));
106         if (SUCCEEDED(hr))
107         {
108             if (GetINetCfgComponent(pNCfg, &pAdapterCfgComp))
109             {
110                 hr = pCompBind->IsBoundTo(pAdapterCfgComp);
111                 if (hr == S_OK)
112                     bChecked = TRUE;
113                 else
114                     bChecked = FALSE;
115             }
116         }
117 
118         pItem = static_cast<NET_ITEM*>(CoTaskMemAlloc(sizeof(NET_ITEM)));
119         if (!pItem)
120             continue;
121 
122         pItem->dwCharacteristics = dwCharacteristics;
123         pItem->szHelp = pHelpText;
124         pItem->Type = (NET_TYPE)Type;
125         pItem->pNCfgComp = pNCfgComp.Detach();
126         pItem->NumPropDialogOpen = 0;
127 
128         AddItemToListView(hDlgCtrl, pItem, pDisplayName, bChecked);
129         CoTaskMemFree(pDisplayName);
130     }
131 }
132 
133 VOID
134 CNetConnectionPropertyUi::InitializeLANPropertiesUIDlg(HWND hwndDlg)
135 {
136     HRESULT hr;
137     CComPtr<INetCfg> pNCfg;
138     CComPtr<INetCfgLock> pNCfgLock;
139     HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_COMPONENTSLIST);
140     LVCOLUMNW lc;
141     RECT rc;
142     DWORD dwStyle;
143     LPWSTR pDisplayName;
144     LVITEMW li;
145 
146     SendDlgItemMessageW(hwndDlg, IDC_NETCARDNAME, WM_SETTEXT, 0, (LPARAM)m_pProperties->pszwDeviceName);
147     if (m_pProperties->dwCharacter & NCCF_SHOW_ICON)
148     {
149         /* check show item on taskbar*/
150         SendDlgItemMessageW(hwndDlg, IDC_SHOWTASKBAR, BM_SETCHECK, BST_CHECKED, 0);
151     }
152     if (m_pProperties->dwCharacter & NCCF_NOTIFY_DISCONNECTED)
153     {
154         /* check notify item */
155         SendDlgItemMessageW(hwndDlg, IDC_NOTIFYNOCONNECTION, BM_SETCHECK, BST_CHECKED, 0);
156     }
157 
158     memset(&lc, 0, sizeof(LV_COLUMN));
159     lc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
160     lc.fmt = LVCFMT_FIXED_WIDTH;
161     if (GetClientRect(hDlgCtrl, &rc))
162     {
163         lc.mask |= LVCF_WIDTH;
164         lc.cx = rc.right - rc.left;
165     }
166     lc.pszText = (LPWSTR)L"";
167     (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&lc);
168     dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
169     dwStyle = dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES;
170     SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
171 
172     hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(INetCfg, &pNCfg));
173     if (FAILED(hr))
174         return;
175 
176     hr = pNCfg->QueryInterface(IID_PPV_ARG(INetCfgLock, &pNCfgLock));
177     hr = pNCfgLock->AcquireWriteLock(100, L"", &pDisplayName);
178     if (hr == S_FALSE)
179     {
180         CoTaskMemFree(pDisplayName);
181         return;
182     }
183 
184     hr = pNCfg->Initialize(NULL);
185     if (FAILED_UNEXPECTEDLY(hr))
186         return;
187 
188     m_pNCfg = pNCfg;
189     m_NCfgLock = pNCfgLock;
190 
191     EnumComponents(hDlgCtrl, pNCfg, &GUID_DEVCLASS_NETCLIENT, NET_TYPE_CLIENT);
192     EnumComponents(hDlgCtrl, pNCfg, &GUID_DEVCLASS_NETSERVICE, NET_TYPE_SERVICE);
193     EnumComponents(hDlgCtrl, pNCfg, &GUID_DEVCLASS_NETTRANS, NET_TYPE_PROTOCOL);
194 
195     ZeroMemory(&li, sizeof(li));
196     li.mask = LVIF_STATE;
197     li.stateMask = (UINT)-1;
198     li.state = LVIS_FOCUSED|LVIS_SELECTED;
199     (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
200 }
201 
202 VOID
203 CNetConnectionPropertyUi::ShowNetworkComponentProperties(HWND hwndDlg)
204 {
205     LVITEMW lvItem;
206     HWND hDlgCtrl;
207     UINT Index, Count;
208     HRESULT hr;
209     INetCfgComponent *pNCfgComp;
210     PNET_ITEM pItem;
211 
212     hDlgCtrl = GetDlgItem(hwndDlg, IDC_COMPONENTSLIST);
213     Count = ListView_GetItemCount(hDlgCtrl);
214     if (!Count)
215         return;
216 
217     ZeroMemory(&lvItem, sizeof(LVITEMW));
218     lvItem.mask = LVIF_PARAM | LVIF_STATE;
219     lvItem.stateMask = (UINT)-1;
220     for (Index = 0; Index < Count; Index++)
221     {
222         lvItem.iItem = Index;
223         if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&lvItem))
224         {
225             if (lvItem.state & LVIS_SELECTED)
226                 break;
227         }
228     }
229 
230     if (!(lvItem.state & LVIS_SELECTED))
231     {
232         return;
233     }
234 
235     pItem = (PNET_ITEM)lvItem.lParam;
236     pNCfgComp = (INetCfgComponent*)pItem->pNCfgComp;
237     hr = pNCfgComp->RaisePropertyUi(GetParent(hwndDlg), NCRP_QUERY_PROPERTY_UI, (INetConnectionConnectUi*)this);
238     if (SUCCEEDED(hr))
239     {
240         hr = pNCfgComp->RaisePropertyUi(GetParent(hwndDlg), NCRP_SHOW_PROPERTY_UI, (INetConnectionConnectUi*)this);
241     }
242 }
243 
244 INT_PTR
245 CALLBACK
246 CNetConnectionPropertyUi::LANPropertiesUIDlg(
247     HWND hwndDlg,
248     UINT uMsg,
249     WPARAM wParam,
250     LPARAM lParam)
251 {
252     PROPSHEETPAGE *page;
253     LPNMLISTVIEW lppl;
254     LVITEMW li;
255     PNET_ITEM pItem;
256     CNetConnectionPropertyUi * This;
257     LPPSHNOTIFY lppsn;
258     DWORD dwShowIcon, dwNotifyDisconnect;
259     HRESULT hr;
260     WCHAR szKey[200];
261     LPOLESTR pStr;
262     HKEY hKey;
263 
264     switch (uMsg)
265     {
266         case WM_INITDIALOG:
267             page = (PROPSHEETPAGE*)lParam;
268             This = (CNetConnectionPropertyUi*)page->lParam;
269             This->InitializeLANPropertiesUIDlg(hwndDlg);
270             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)This);
271             return TRUE;
272         case WM_NOTIFY:
273             lppl = (LPNMLISTVIEW) lParam;
274             lppsn = (LPPSHNOTIFY) lParam;
275             if (lppsn->hdr.code == PSN_APPLY)
276             {
277                 This = (CNetConnectionPropertyUi*)GetWindowLongPtr(hwndDlg, DWLP_USER);
278                 if (This->m_pNCfg)
279                 {
280                     hr = This->m_pNCfg->Apply();
281                     if (FAILED(hr))
282                         return PSNRET_INVALID;
283                 }
284 
285                 if (SendDlgItemMessageW(hwndDlg, IDC_SHOWTASKBAR, BM_GETCHECK, 0, 0) == BST_CHECKED)
286                     dwShowIcon = 1;
287                 else
288                     dwShowIcon = 0;
289 
290                 if (SendDlgItemMessageW(hwndDlg, IDC_NOTIFYNOCONNECTION, BM_GETCHECK, 0, 0) == BST_CHECKED)
291                     dwNotifyDisconnect = 1;
292                 else
293                     dwNotifyDisconnect = 0;
294 
295                 //NOTE: Windows write these setting with the undocumented INetLanConnection::SetInfo
296                 if (StringFromCLSID((CLSID)This->m_pProperties->guidId, &pStr) == ERROR_SUCCESS)
297                 {
298                     swprintf(szKey, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", pStr);
299                     CoTaskMemFree(pStr);
300                     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKey, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
301                     {
302                         RegSetValueExW(hKey, L"ShowIcon", 0, REG_DWORD, (LPBYTE)&dwShowIcon, sizeof(DWORD));
303                         RegSetValueExW(hKey, L"IpCheckingEnabled", 0, REG_DWORD, (LPBYTE)&dwNotifyDisconnect, sizeof(DWORD));
304                         RegCloseKey(hKey);
305                     }
306                 }
307 
308                 return PSNRET_NOERROR;
309             }
310 #if 0
311             else if (lppsn->hdr.code == PSN_CANCEL)
312             {
313                 This = (CNetConnectionPropertyUi*)GetWindowLongPtr(hwndDlg, DWLP_USER);
314                 if (This->m_pNCfg)
315                 {
316                     hr = This->m_pNCfg->Cancel();
317                     if (SUCCEEDED(hr))
318                         return PSNRET_NOERROR;
319                     else
320                         return PSNRET_INVALID;
321                 }
322                 return PSNRET_NOERROR;
323             }
324 #endif
325             if (lppl->hdr.code == LVN_ITEMCHANGING)
326             {
327                 ZeroMemory(&li, sizeof(li));
328                 li.mask = LVIF_PARAM;
329                 li.iItem = lppl->iItem;
330                 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&li))
331                     return TRUE;
332 
333                 pItem = (PNET_ITEM)li.lParam;
334                 if (!pItem)
335                     return TRUE;
336 
337                 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
338                 {
339                     /* new focused item */
340                     if (pItem->dwCharacteristics & NCF_NOT_USER_REMOVABLE)
341                         EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTALL), FALSE);
342                     else
343                         EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTALL), TRUE);
344 
345                     if (pItem->dwCharacteristics & NCF_HAS_UI)
346                         EnableWindow(GetDlgItem(hwndDlg, IDC_PROPERTIES), TRUE);
347                     else
348                         EnableWindow(GetDlgItem(hwndDlg, IDC_PROPERTIES), FALSE);
349 
350                     SendDlgItemMessageW(hwndDlg, IDC_DESCRIPTION, WM_SETTEXT, 0, (LPARAM)pItem->szHelp);
351                 }
352             }
353             break;
354         case WM_COMMAND:
355             if (LOWORD(wParam) == IDC_PROPERTIES)
356             {
357                 This = (CNetConnectionPropertyUi*) GetWindowLongPtr(hwndDlg, DWLP_USER);
358                 This->ShowNetworkComponentProperties(hwndDlg);
359                 return FALSE;
360             }
361             else if (LOWORD(wParam) == IDC_CONFIGURE)
362             {
363                 LPOLESTR DeviceInstanceID;
364                 This = (CNetConnectionPropertyUi*)GetWindowLongPtr(hwndDlg, DWLP_USER);
365 
366                 if (This->GetDeviceInstanceID(&DeviceInstanceID))
367                 {
368                     WCHAR wszCmd[2*MAX_PATH];
369                     StringCbPrintfW(wszCmd, sizeof(wszCmd), L"rundll32.exe devmgr.dll,DeviceProperties_RunDLL /DeviceID %s", DeviceInstanceID);
370                     CoTaskMemFree(DeviceInstanceID);
371 
372                     STARTUPINFOW si;
373                     PROCESS_INFORMATION pi;
374                     ZeroMemory(&si, sizeof(si));
375                     si.cb = sizeof(si);
376                     if (!CreateProcessW(NULL, wszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
377                         break;
378 
379                    CloseHandle(pi.hProcess);
380                    CloseHandle(pi.hThread);
381                 }
382             }
383             break;
384     }
385     return FALSE;
386 }
387 
388 BOOL
389 CNetConnectionPropertyUi::GetDeviceInstanceID(
390     OUT LPOLESTR *DeviceInstanceID)
391 {
392     LPOLESTR pStr, pResult;
393     HKEY hKey;
394     DWORD dwInstanceID;
395     WCHAR szKeyName[2*MAX_PATH];
396     WCHAR szInstanceID[2*MAX_PATH];
397 
398     if (StringFromCLSID(m_pProperties->guidId, &pStr) != ERROR_SUCCESS)
399     {
400         // failed to convert guid to string
401         return FALSE;
402     }
403 
404     StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", pStr);
405     CoTaskMemFree(pStr);
406 
407     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
408     {
409         // failed to open key
410         return FALSE;
411     }
412 
413     dwInstanceID = sizeof(szInstanceID);
414     if (RegGetValueW(hKey, NULL, L"PnpInstanceId", RRF_RT_REG_SZ, NULL, (PVOID)szInstanceID, &dwInstanceID) == ERROR_SUCCESS)
415     {
416         szInstanceID[MAX_PATH-1] = L'\0';
417         pResult = static_cast<LPOLESTR>(CoTaskMemAlloc((wcslen(szInstanceID) + 1) * sizeof(WCHAR)));
418         if (pResult != 0)
419         {
420             wcscpy(pResult, szInstanceID);
421             *DeviceInstanceID = pResult;
422             RegCloseKey(hKey);
423             return TRUE;
424         }
425     }
426     RegCloseKey(hKey);
427     return FALSE;
428 }
429 
430 HRESULT
431 WINAPI
432 CNetConnectionPropertyUi::AddPages(
433     HWND hwndParent,
434     LPFNADDPROPSHEETPAGE pfnAddPage,
435     LPARAM lParam)
436 {
437     HPROPSHEETPAGE hProp;
438     BOOL ret;
439     HRESULT hr = E_FAIL;
440     INITCOMMONCONTROLSEX initEx;
441 
442     initEx.dwSize = sizeof(initEx);
443     initEx.dwICC = ICC_LISTVIEW_CLASSES;
444     if (!InitCommonControlsEx(&initEx))
445         return E_FAIL;
446 
447     hr = m_pCon->GetProperties(&m_pProperties);
448     if (FAILED_UNEXPECTEDLY(hr))
449         return hr;
450 
451     hProp = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_NETPROPERTIES), LANPropertiesUIDlg, reinterpret_cast<LPARAM>(this), NULL);
452     if (hProp)
453     {
454         ret = (*pfnAddPage)(hProp, lParam);
455         if (ret)
456         {
457             hr = NOERROR;
458         }
459         else
460         {
461             DestroyPropertySheetPage(hProp);
462         }
463     }
464     return hr;
465 }
466 
467 HRESULT
468 WINAPI
469 CNetConnectionPropertyUi::GetIcon(
470     DWORD dwSize,
471     HICON *phIcon)
472 {
473     return E_NOTIMPL;
474 }
475 
476 HRESULT
477 WINAPI
478 CNetConnectionPropertyUi::GetDeviceGuid(GUID *pGuid)
479 {
480     CopyMemory(pGuid, &m_pProperties->guidId, sizeof(GUID));
481     return S_OK;
482 }
483 
484 HRESULT
485 WINAPI
486 CNetConnectionPropertyUi::SetConnection(INetConnection* pCon)
487 {
488     if (!pCon)
489         return E_POINTER;
490 
491     m_pCon = pCon;
492     return S_OK;
493 }
494 
495 HRESULT
496 WINAPI
497 CNetConnectionPropertyUi::Connect(
498     HWND hwndParent,
499     DWORD dwFlags)
500 {
501     if (!m_pCon)
502         return E_POINTER; //FIXME
503 
504     if (dwFlags & NCUC_NO_UI)
505         return m_pCon->Connect();
506 
507     return E_FAIL;
508 }
509 
510 HRESULT
511 WINAPI
512 CNetConnectionPropertyUi::Disconnect(
513     HWND hwndParent,
514     DWORD dwFlags)
515 {
516     WCHAR szBuffer[100];
517     swprintf(szBuffer, L"INetConnectionConnectUi_fnDisconnect flags %x\n", dwFlags);
518     MessageBoxW(NULL, szBuffer, NULL, MB_OK);
519 
520     return S_OK;
521 }
522