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