[NETSHELL] Improvements to the network setup (2a/x)
[reactos.git] / dll / shellext / netshell / lanconnectui.cpp
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 }