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