Reactos
1/*
2 * PROJECT: ReactOS Shell
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: ReactOS Networking Configuration
5 * COPYRIGHT: Copyright 2016 Eric Kohl
6 */
7
8#include "precomp.h"
9
10#include <syssetup/syssetup.h>
11
12
13#define NETWORK_SETUP_MAGIC 0x50515253
14
15typedef struct _NETWORKSETUPDATA
16{
17 DWORD dwMagic;
18 PSETUPDATA pSetupData;
19
20 /* settings page data */
21 BOOL bInitialSetupRun;
22 BOOL bTypicalNetworkSetup;
23 HWND hwndPage;
24} NETWORKSETUPDATA, *PNETWORKSETUPDATA;
25
26extern "C"
27{
28
29typedef struct _NETWORKCOMPONENT
30{
31 LPWSTR pszDeviceId;
32 const GUID *pClassGuid;
33} NETWORKCOMPONENT, PNETWORKCOMPONENT;
34
35static NETWORKCOMPONENT NetworkComponents[] = {
36 {(LPWSTR)L"MS_TCPIP", &GUID_DEVCLASS_NETTRANS},
37 {(LPWSTR)L"MS_NDISUIO", &GUID_DEVCLASS_NETTRANS}
38};
39
40
41static
42VOID
43SetBoldText(
44 HWND hwndDlg,
45 INT control,
46 PSETUPDATA pSetupData)
47{
48 SendDlgItemMessageW(hwndDlg, control, WM_SETFONT, (WPARAM)pSetupData->hBoldFont, MAKELPARAM(TRUE, 0));
49}
50
51
52static
53HRESULT
54InstallNetworkComponent(
55 LPWSTR pszComponentName,
56 const GUID *pClassGuid)
57{
58 INetCfg *pNetCfg = NULL;
59 INetCfgLock *pNetCfgLock = NULL;
60 INetCfgClassSetup *pNetCfgClassSetup = NULL;
61 INetCfgComponent *pNetCfgComponent = NULL;
62 BOOL fWriteLocked = FALSE, fInitialized = FALSE;
63 OBO_TOKEN OboToken;
64 HRESULT hr;
65
66 TRACE("InstallNetworkComponent(%S)\n", pszComponentName);
67
68 hr = CoInitialize(NULL);
69 if (hr != S_OK)
70 {
71 ERR("CoInitialize failed\n");
72 goto exit;
73 }
74
75 hr = CoCreateInstance(CLSID_CNetCfg,
76 NULL,
77 CLSCTX_INPROC_SERVER,
78 IID_INetCfg,
79 (PVOID*)&pNetCfg);
80 if (hr != S_OK)
81 {
82 ERR("CoCreateInstance failed\n");
83 goto exit;
84 }
85
86 /* Acquire the write-lock */
87 hr = pNetCfg->QueryInterface(IID_INetCfgLock,
88 (PVOID*)&pNetCfgLock);
89 if (hr != S_OK)
90 {
91 ERR("QueryInterface failed\n");
92 goto exit;
93 }
94
95 hr = pNetCfgLock->AcquireWriteLock(5000,
96 L"SysSetup",
97 NULL);
98 if (hr != S_OK)
99 {
100 ERR("AcquireWriteLock failed\n");
101 goto exit;
102 }
103
104 fWriteLocked = TRUE;
105
106 /* Initialize the network configuration */
107 hr = pNetCfg->Initialize(NULL);
108 if (hr != S_OK)
109 {
110 ERR("Initialize failed\n");
111 goto exit;
112 }
113
114 fInitialized = TRUE;
115
116 hr = pNetCfg->QueryNetCfgClass(pClassGuid,
117 IID_INetCfgClassSetup,
118 (PVOID*)&pNetCfgClassSetup);
119 if (hr != S_OK)
120 {
121 ERR("QueryNetCfgClass failed\n");
122 goto exit;
123 }
124
125 ZeroMemory(&OboToken, sizeof(OboToken));
126 OboToken.Type = OBO_USER;
127
128 hr = pNetCfgClassSetup->Install(pszComponentName,
129 &OboToken,
130 0, //NSF_PRIMARYINSTALL,
131 0,
132 NULL,
133 NULL,
134 &pNetCfgComponent);
135 if (hr == S_OK)
136 {
137 if (pNetCfgComponent != NULL)
138 pNetCfgComponent->Release();
139 }
140 else
141 {
142 ERR("Install failed\n");
143 goto exit;
144 }
145
146 hr = pNetCfg->Apply();
147 if (hr != S_OK)
148 {
149 ERR("Apply failed\n");
150 goto exit;
151 }
152
153exit:
154 if (pNetCfgClassSetup != NULL)
155 pNetCfgClassSetup->Release();
156
157 if (fInitialized)
158 pNetCfg->Uninitialize();
159
160 if (fWriteLocked)
161 pNetCfgLock->ReleaseWriteLock();
162
163 if (pNetCfgLock != NULL)
164 pNetCfgLock->Release();
165
166 if (pNetCfg != NULL)
167 pNetCfg->Release();
168
169 CoUninitialize();
170
171 TRACE("InstallNetworkComponent() done!\n");
172
173 return hr;
174}
175
176static
177DWORD
178WINAPI
179InstallThreadProc(
180 _In_ LPVOID lpParameter)
181{
182 PNETWORKSETUPDATA pNetworkSetupData = (PNETWORKSETUPDATA)lpParameter;
183 UINT i, count;
184
185 TRACE("InstallThreadProc()\n");
186
187 count = sizeof(NetworkComponents) / sizeof(NETWORKCOMPONENT);
188 TRACE("Network Components: %u\n", count);
189
190 SendDlgItemMessage(pNetworkSetupData->hwndPage, IDC_INSTALL_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, count));
191 SendDlgItemMessage(pNetworkSetupData->hwndPage, IDC_INSTALL_PROGRESS, PBM_SETPOS, 0, 0);
192
193 for (i = 0; i < count; i++)
194 {
195 TRACE("Install Network Component: %S\n", NetworkComponents[i].pszDeviceId);
196 InstallNetworkComponent(NetworkComponents[i].pszDeviceId, NetworkComponents[i].pClassGuid);
197 SendDlgItemMessage(pNetworkSetupData->hwndPage, IDC_INSTALL_PROGRESS, PBM_SETPOS, i, 0);
198 Sleep(500);
199 }
200
201 TRACE("Done\n");
202
203 /* Done */
204 pNetworkSetupData->bInitialSetupRun = TRUE;
205 PostMessage(pNetworkSetupData->hwndPage, WM_USER, 0, 0);
206
207 return 0;
208}
209
210static
211INT_PTR
212CALLBACK
213NetworkInitPageDlgProc(
214 HWND hwndDlg,
215 UINT uMsg,
216 WPARAM wParam,
217 LPARAM lParam)
218{
219 PNETWORKSETUPDATA pNetworkSetupData;
220 PSETUPDATA pSetupData;
221 LPNMHDR lpnm;
222
223 /* Retrieve pointer to the global setup data */
224 pNetworkSetupData = (PNETWORKSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
225 if ((pNetworkSetupData != NULL) &&
226 (pNetworkSetupData->dwMagic == NETWORK_SETUP_MAGIC))
227 pSetupData = pNetworkSetupData->pSetupData;
228
229 switch (uMsg)
230 {
231 case WM_INITDIALOG:
232 /* Save pointer to the global setup data */
233 pNetworkSetupData = (PNETWORKSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
234 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pNetworkSetupData);
235 pSetupData = pNetworkSetupData->pSetupData;
236
237 if (pSetupData->UnattendSetup)
238 {
239 //...
240 }
241 break;
242
243 case WM_DESTROY:
244 /* ATTENTION: Free pNetworkSetupData only in one of the page functions!!! */
245 //...
246 break;
247
248 case WM_NOTIFY:
249 lpnm = (LPNMHDR)lParam;
250
251 switch (lpnm->code)
252 {
253 case PSN_SETACTIVE:
254 /* Disable the Back and Next buttons */
255 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
256 TRACE("Starting install thread!\n");
257 pNetworkSetupData->hwndPage = hwndDlg;
258 CreateThread(NULL, 0, InstallThreadProc, (LPVOID)pNetworkSetupData, 0, NULL);
259 TRACE("Install thread done!\n");
260 break;
261
262 case PSN_WIZNEXT:
263 break;
264
265 case PSN_WIZBACK:
266 break;
267 }
268 break;
269
270 case WM_USER:
271 TRACE("WM_USER!\n");
272 /* Enable the Next button and press it */
273 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
274 PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
275 break;
276
277 default:
278 break;
279 }
280
281 return FALSE;
282}
283
284static
285INT_PTR
286CALLBACK
287NetworkSettingsPageDlgProc(
288 HWND hwndDlg,
289 UINT uMsg,
290 WPARAM wParam,
291 LPARAM lParam)
292{
293 PNETWORKSETUPDATA pNetworkSetupData;
294 PSETUPDATA pSetupData;
295 LPNMHDR lpnm;
296
297 /* Retrieve pointer to the global setup data */
298 pNetworkSetupData = (PNETWORKSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
299 if ((pNetworkSetupData != NULL) &&
300 (pNetworkSetupData->dwMagic == NETWORK_SETUP_MAGIC))
301 pSetupData = pNetworkSetupData->pSetupData;
302
303 switch (uMsg)
304 {
305 case WM_INITDIALOG:
306 /* Save pointer to the global setup data */
307 pNetworkSetupData = (PNETWORKSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
308 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pNetworkSetupData);
309 pSetupData = pNetworkSetupData->pSetupData;
310
311 /* Set the fonts of both the options to bold */
312 SetBoldText(hwndDlg, IDC_NETWORK_TYPICAL, pSetupData);
313 SetBoldText(hwndDlg, IDC_NETWORK_CUSTOM, pSetupData);
314
315 /* Set the typical settings option as the default */
316 SendDlgItemMessage(hwndDlg, IDC_NETWORK_TYPICAL, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
317
318 if (pSetupData->UnattendSetup)
319 {
320 //...
321 }
322 break;
323
324 case WM_DESTROY:
325 /* ATTENTION: Free pNetworkSetupData only in one of the page functions!!! */
326 //...
327 break;
328
329 case WM_NOTIFY:
330 lpnm = (LPNMHDR)lParam;
331
332 switch (lpnm->code)
333 {
334 case PSN_SETACTIVE:
335 /* Enable the Next button only */
336 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
337 if (pSetupData->UnattendSetup)
338 {
339 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_NETWORKCOMPONENTPAGE);
340 return TRUE;
341 }
342 break;
343
344 case PSN_WIZNEXT:
345 pNetworkSetupData->bTypicalNetworkSetup = FALSE;
346
347 /* If the Typical Settings button is chosen, then skip to the Domain Page */
348 if (IsDlgButtonChecked(hwndDlg, IDC_NETWORK_TYPICAL) == BST_CHECKED)
349 {
350 pNetworkSetupData->bTypicalNetworkSetup = TRUE;
351
352 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_NETWORKDOMAINPAGE);
353 return TRUE;
354 }
355 break;
356
357 case PSN_WIZBACK:
358 pSetupData->UnattendSetup = FALSE;
359 break;
360 }
361 break;
362
363 default:
364 break;
365 }
366
367 return FALSE;
368}
369
370static
371INT_PTR
372CALLBACK
373NetworkComponentPageDlgProc(
374 HWND hwndDlg,
375 UINT uMsg,
376 WPARAM wParam,
377 LPARAM lParam)
378{
379 PNETWORKSETUPDATA pNetworkSetupData;
380 PSETUPDATA pSetupData;
381 LPNMHDR lpnm;
382
383 /* Retrieve pointer to the global setup data */
384 pNetworkSetupData = (PNETWORKSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
385 if ((pNetworkSetupData != NULL) &&
386 (pNetworkSetupData->dwMagic == NETWORK_SETUP_MAGIC))
387 pSetupData = pNetworkSetupData->pSetupData;
388
389 switch (uMsg)
390 {
391 case WM_INITDIALOG:
392 /* Save pointer to the global setup data */
393 pNetworkSetupData = (PNETWORKSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
394 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pNetworkSetupData);
395 pSetupData = pNetworkSetupData->pSetupData;
396
397 SetBoldText(hwndDlg, IDC_NETWORK_DEVICE, pSetupData);
398
399 if (pSetupData->UnattendSetup)
400 {
401 //...
402 }
403 break;
404
405 case WM_DESTROY:
406 /* ATTENTION: Free pNetworkSetupData only in one of the page functions!!! */
407 //...
408 break;
409
410 case WM_NOTIFY:
411 lpnm = (LPNMHDR)lParam;
412
413 switch (lpnm->code)
414 {
415 case PSN_SETACTIVE:
416 /* Enable the Back and Next buttons */
417 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
418 if (pSetupData->UnattendSetup)
419 {
420 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_NETWORKDOMAINPAGE);
421 return TRUE;
422 }
423 break;
424
425 case PSN_WIZBACK:
426 pSetupData->UnattendSetup = FALSE;
427 break;
428 }
429 break;
430
431 default:
432 break;
433 }
434
435 return FALSE;
436}
437
438static
439INT_PTR
440CALLBACK
441NetworkDomainPageDlgProc(
442 HWND hwndDlg,
443 UINT uMsg,
444 WPARAM wParam,
445 LPARAM lParam)
446{
447 PNETWORKSETUPDATA pNetworkSetupData;
448 PSETUPDATA pSetupData;
449 WCHAR DomainName[51];
450 WCHAR Title[64];
451 WCHAR ErrorName[256];
452 LPNMHDR lpnm;
453
454 /* Retrieve pointer to the global setup data */
455 pNetworkSetupData = (PNETWORKSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
456 if ((pNetworkSetupData != NULL) &&
457 (pNetworkSetupData->dwMagic == NETWORK_SETUP_MAGIC))
458 pSetupData = pNetworkSetupData->pSetupData;
459
460 switch (uMsg)
461 {
462 case WM_INITDIALOG:
463 /* Save pointer to the global setup data */
464 pNetworkSetupData = (PNETWORKSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
465 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pNetworkSetupData);
466 pSetupData = pNetworkSetupData->pSetupData;
467
468 /* Set the workgroup option as the default */
469 SendDlgItemMessage(hwndDlg, IDC_SELECT_WORKGROUP, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
470
471 wcscpy(DomainName, L"WORKGROUP");
472
473 /* Display current computer name */
474 SetDlgItemTextW(hwndDlg, IDC_DOMAIN_NAME, DomainName);
475
476 /* Set focus to owner name */
477 SetFocus(GetDlgItem(hwndDlg, IDC_DOMAIN_NAME));
478
479 if (pSetupData->UnattendSetup)
480 {
481 //...
482 }
483 break;
484
485 case WM_DESTROY:
486 //...
487 /* ATTENTION: Free pNetworkSetupData only in one of the page functions!!! */
488 if (pNetworkSetupData != NULL)
489 {
490 if ((!IsBadReadPtr(pNetworkSetupData, sizeof(NETWORKSETUPDATA))) &&
491 (pNetworkSetupData->dwMagic == NETWORK_SETUP_MAGIC))
492 HeapFree(GetProcessHeap(), 0, pNetworkSetupData);
493
494 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)NULL);
495 }
496 break;
497
498 case WM_NOTIFY:
499 lpnm = (LPNMHDR)lParam;
500
501 switch (lpnm->code)
502 {
503 case PSN_SETACTIVE:
504 /* Enable the Back and Next buttons */
505 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
506 if (pSetupData->UnattendSetup)
507 {
508 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, pSetupData->uPostNetworkWizardPage);
509 return TRUE;
510 }
511 break;
512
513 case PSN_WIZNEXT:
514 DomainName[0] = 0;
515 if (GetDlgItemTextW(hwndDlg, IDC_DOMAIN_NAME, DomainName, 50) == 0)
516 {
517 if (0 == LoadStringW(netshell_hInstance, IDS_REACTOS_SETUP, Title, sizeof(Title) / sizeof(Title[0])))
518 {
519 wcscpy(Title, L"ReactOS Setup");
520 }
521 if (0 == LoadStringW(netshell_hInstance, IDS_WZD_DOMAIN_NAME, ErrorName, sizeof(ErrorName) / sizeof(ErrorName[0])))
522 {
523 wcscpy(ErrorName, L"Setup cannot continue until you\nenter the name of your domain/workgroup.");
524 }
525 MessageBoxW(hwndDlg, ErrorName, Title, MB_ICONERROR | MB_OK);
526
527 SetFocus(GetDlgItem(hwndDlg, IDC_DOMAIN_NAME));
528 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
529
530 //TODO: Implement setting the Domain/Workgroup
531
532 return TRUE;
533 }
534 break;
535
536 case PSN_WIZBACK:
537 pSetupData->UnattendSetup = FALSE;
538
539 /* If the Typical setup chosen, then skip back to the Settings Page */
540 if (pNetworkSetupData->bTypicalNetworkSetup == TRUE)
541 {
542 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_NETWORKSETTINGSPAGE);
543 return TRUE;
544 }
545 break;
546 }
547 break;
548
549 default:
550 break;
551 }
552
553 return FALSE;
554}
555
556
557DWORD
558WINAPI
559NetSetupRequestWizardPages(
560 PDWORD pPageCount,
561 HPROPSHEETPAGE *pPages,
562 PSETUPDATA pSetupData)
563{
564 PNETWORKSETUPDATA pNetworkSetupData;
565 PROPSHEETPAGE psp = {0};
566 DWORD dwPageCount = 4;
567 INT nPage = 0;
568
569 TRACE("NetSetupRequestWizardPages(%p %p %p)\n", pPageCount, pPages, pSetupData);
570
571 if (pPageCount == NULL)
572 return ERROR_INVALID_PARAMETER;
573
574 if (pPages == NULL)
575 {
576 TRACE("Return %lu pages\n", dwPageCount);
577 *pPageCount = dwPageCount;
578 return ERROR_SUCCESS;
579 }
580
581 if (*pPageCount < dwPageCount)
582 return ERROR_BUFFER_OVERFLOW;
583
584 pSetupData->uFirstNetworkWizardPage = IDD_NETWORKINITPAGE;
585
586 pNetworkSetupData = (PNETWORKSETUPDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NETWORKSETUPDATA));
587 if (pNetworkSetupData == NULL)
588 return ERROR_OUTOFMEMORY;
589
590 pNetworkSetupData->dwMagic = NETWORK_SETUP_MAGIC;
591 pNetworkSetupData->pSetupData = pSetupData;
592
593 /* Create the Network Settings page */
594 psp.dwSize = sizeof(PROPSHEETPAGE);
595 psp.hInstance = netshell_hInstance;
596 psp.lParam = (LPARAM)pNetworkSetupData;
597
598 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
599 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_NETWORKINITTITLE);
600 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_NETWORKINITSUBTITLE);
601 psp.pfnDlgProc = NetworkInitPageDlgProc;
602 psp.pszTemplate = MAKEINTRESOURCE(IDD_NETWORKINITPAGE);
603 pPages[nPage++] = CreatePropertySheetPage(&psp);
604
605 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
606 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_NETWORKSETTINGSTITLE);
607 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_NETWORKSETTINGSSUBTITLE);
608 psp.pfnDlgProc = NetworkSettingsPageDlgProc;
609 psp.pszTemplate = MAKEINTRESOURCE(IDD_NETWORKSETTINGSPAGE);
610 pPages[nPage++] = CreatePropertySheetPage(&psp);
611
612 /* Create the Network Components page */
613 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
614 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_NETWORKCOMPONENTTITLE);
615 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_NETWORKCOMPONENTSUBTITLE);
616 psp.pfnDlgProc = NetworkComponentPageDlgProc;
617 psp.pszTemplate = MAKEINTRESOURCE(IDD_NETWORKCOMPONENTPAGE);
618 pPages[nPage++] = CreatePropertySheetPage(&psp);
619
620 /* Create the Domain/Workgroup page */
621 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
622 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_NETWORKDOMAINTITLE);
623 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_NETWORKDOMAINSUBTITLE);
624 psp.pfnDlgProc = NetworkDomainPageDlgProc;
625 psp.pszTemplate = MAKEINTRESOURCE(IDD_NETWORKDOMAINPAGE);
626 pPages[nPage++] = CreatePropertySheetPage(&psp);
627
628 TRACE("Return %lu pages\n", dwPageCount);
629 *pPageCount = dwPageCount;
630
631 return ERROR_SUCCESS;
632}
633
634} // extern "C"