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