Add message box to tell the user to reboot after the installation of a network card
[reactos.git] / reactos / lib / netcfgx / netcfgx.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Configuration of networkd devices
4 * FILE: lib/netcfgx/netcfgx.c
5 * PURPOSE: Network devices installer
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #include "netcfgx.h"
14
15 /* Append a REG_SZ to an existing REG_MULTI_SZ string in the registry.
16 * If the value doesn't exist, create it.
17 * Returns ERROR_SUCCESS if success. Othewise, returns an error code
18 */
19 static LONG
20 AppendStringToMultiSZ(
21 IN HKEY hKey,
22 IN PCWSTR ValueName,
23 IN PCWSTR ValueToAppend)
24 {
25 PWSTR Buffer = NULL;
26 DWORD dwRegType;
27 DWORD dwRequired, dwLength;
28 DWORD dwTmp;
29 LONG rc;
30
31 rc = RegQueryValueExW(
32 hKey,
33 ValueName,
34 NULL,
35 &dwRegType,
36 NULL,
37 &dwRequired);
38 if (rc != ERROR_FILE_NOT_FOUND)
39 {
40 if (rc != ERROR_SUCCESS)
41 goto cleanup;
42 if (dwRegType != REG_MULTI_SZ)
43 {
44 rc = ERROR_GEN_FAILURE;
45 goto cleanup;
46 }
47
48 dwTmp = dwLength = dwRequired + wcslen(ValueToAppend) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
49 Buffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
50 if (!Buffer)
51 {
52 rc = ERROR_NOT_ENOUGH_MEMORY;
53 goto cleanup;
54 }
55 rc = RegQueryValueExW(
56 hKey,
57 ValueName,
58 NULL,
59 NULL,
60 (BYTE*)Buffer,
61 &dwTmp);
62 if (rc != ERROR_SUCCESS)
63 goto cleanup;
64 }
65 else
66 {
67 dwRequired = sizeof(WCHAR);
68 dwLength = wcslen(ValueToAppend) * sizeof(WCHAR) + 2 * sizeof(UNICODE_NULL);
69 Buffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
70 if (!Buffer)
71 {
72 rc = ERROR_NOT_ENOUGH_MEMORY;
73 goto cleanup;
74 }
75 }
76
77 /* Append the value */
78 wcscpy(&Buffer[dwRequired / sizeof(WCHAR) - 1], ValueToAppend);
79 /* Terminate the REG_MULTI_SZ string */
80 Buffer[dwLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
81
82 rc = RegSetValueExW(
83 hKey,
84 ValueName,
85 0,
86 REG_MULTI_SZ,
87 (const BYTE*)Buffer,
88 dwLength);
89
90 cleanup:
91 HeapFree(GetProcessHeap(), 0, Buffer);
92 return rc;
93 }
94
95 DWORD WINAPI
96 NetClassInstaller(
97 IN DI_FUNCTION InstallFunction,
98 IN HDEVINFO DeviceInfoSet,
99 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
100 {
101 RPC_STATUS RpcStatus;
102 UUID Uuid;
103 LPWSTR InstanceId = NULL;
104 LPWSTR UuidRpcString = NULL;
105 LPWSTR UuidString = NULL;
106 LPWSTR DeviceName = NULL;
107 LPWSTR ExportName = NULL;
108 LONG rc;
109 DWORD dwShowIcon, dwLength;
110 HKEY hKey = INVALID_HANDLE_VALUE;
111 HKEY hLinkageKey = INVALID_HANDLE_VALUE;
112 HKEY hNetworkKey = INVALID_HANDLE_VALUE;
113 HKEY hConnectionKey = INVALID_HANDLE_VALUE;
114
115 if (InstallFunction != DIF_INSTALLDEVICE)
116 return ERROR_DI_DO_DEFAULT;
117
118 DPRINT("%lu %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
119
120 /* Get Instance ID */
121 if (SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, NULL, 0, &dwLength))
122 {
123 DPRINT("SetupDiGetDeviceInstanceIdW() returned TRUE. FALSE expected\n");
124 rc = ERROR_GEN_FAILURE;
125 goto cleanup;
126 }
127 InstanceId = HeapAlloc(GetProcessHeap(), 0, dwLength);
128 if (!InstanceId)
129 {
130 DPRINT("HeapAlloc() failed\n");
131 rc = ERROR_NOT_ENOUGH_MEMORY;
132 goto cleanup;
133 }
134 if (!SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, InstanceId, dwLength, NULL))
135 {
136 rc = GetLastError();
137 DPRINT("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", rc);
138 goto cleanup;
139 }
140
141 /* Create a new UUID */
142 RpcStatus = UuidCreate(&Uuid);
143 if (RpcStatus != RPC_S_OK && RpcStatus != RPC_S_UUID_LOCAL_ONLY)
144 {
145 DPRINT("UuidCreate() failed with RPC status 0x%lx\n", RpcStatus);
146 rc = ERROR_GEN_FAILURE;
147 goto cleanup;
148 }
149 RpcStatus = UuidToStringW(&Uuid, &UuidRpcString);
150 if (RpcStatus != RPC_S_OK)
151 {
152 DPRINT("UuidToStringW() failed with RPC status 0x%lx\n", RpcStatus);
153 rc = ERROR_GEN_FAILURE;
154 goto cleanup;
155 }
156
157 /* Add curly braces around Uuid */
158 UuidString = HeapAlloc(GetProcessHeap(), 0, (2 + wcslen(UuidRpcString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
159 if (!UuidString)
160 {
161 DPRINT("HeapAlloc() failed\n");
162 rc = ERROR_NOT_ENOUGH_MEMORY;
163 goto cleanup;
164 }
165 wcscpy(UuidString, L"{");
166 wcscat(UuidString, UuidRpcString);
167 wcscat(UuidString, L"}");
168
169 /* Create device name */
170 DeviceName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
171 if (!DeviceName)
172 {
173 DPRINT("HeapAlloc() failed\n");
174 rc = ERROR_NOT_ENOUGH_MEMORY;
175 goto cleanup;
176 }
177 wcscpy(DeviceName, L"\\Device\\");
178 wcscat(DeviceName, UuidString);
179
180 /* Create export name */
181 ExportName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\Tcpip_") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
182 if (!ExportName)
183 {
184 DPRINT("HeapAlloc() failed\n");
185 rc = ERROR_NOT_ENOUGH_MEMORY;
186 goto cleanup;
187 }
188 wcscpy(ExportName, L"\\Device\\Tcpip_");
189 wcscat(ExportName, UuidString);
190
191 /* Write Tcpip parameters in new service Key */
192 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services", 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hKey, NULL);
193 if (rc != ERROR_SUCCESS)
194 {
195 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
196 goto cleanup;
197 }
198 rc = RegCreateKeyExW(hKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hNetworkKey, NULL);
199 if (rc != ERROR_SUCCESS)
200 {
201 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
202 goto cleanup;
203 }
204 RegCloseKey(hKey);
205 hKey = INVALID_HANDLE_VALUE;
206 rc = RegCreateKeyExW(hNetworkKey, L"Parameters\\Tcpip", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL);
207 if (rc != ERROR_SUCCESS)
208 {
209 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
210 goto cleanup;
211 }
212 RegCloseKey(hNetworkKey);
213 hNetworkKey = INVALID_HANDLE_VALUE;
214 rc = RegSetValueExW(hKey, L"DefaultGateway", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
215 if (rc != ERROR_SUCCESS)
216 {
217 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
218 goto cleanup;
219 }
220 rc = RegSetValueExW(hKey, L"IPAddress", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
221 if (rc != ERROR_SUCCESS)
222 {
223 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
224 goto cleanup;
225 }
226 rc = RegSetValueExW(hKey, L"SubnetMask", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
227 if (rc != ERROR_SUCCESS)
228 {
229 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
230 goto cleanup;
231 }
232 RegCloseKey(hKey);
233 hKey = INVALID_HANDLE_VALUE;
234
235 /* Write 'Linkage' key in hardware key */
236 #if _WIN32_WINNT >= 0x502
237 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
238 #else
239 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
240 #endif
241 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
242 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
243 if (hKey == INVALID_HANDLE_VALUE)
244 {
245 rc = GetLastError();
246 DPRINT("SetupDiCreateDevRegKeyW() failed with error 0x%lx\n", rc);
247 goto cleanup;
248 }
249 rc = RegSetValueExW(hKey, L"NetCfgInstanceId", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
250 if (rc != ERROR_SUCCESS)
251 {
252 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
253 goto cleanup;
254 }
255 rc = RegCreateKeyExW(hKey, L"Linkage", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hLinkageKey, NULL);
256 if (rc != ERROR_SUCCESS)
257 {
258 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
259 goto cleanup;
260 }
261 rc = RegSetValueExW(hLinkageKey, L"Export", 0, REG_SZ, (const BYTE*)DeviceName, (wcslen(DeviceName) + 1) * sizeof(WCHAR));
262 if (rc != ERROR_SUCCESS)
263 {
264 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
265 goto cleanup;
266 }
267 rc = RegSetValueExW(hLinkageKey, L"RootDevice", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
268 if (rc != ERROR_SUCCESS)
269 {
270 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
271 goto cleanup;
272 }
273 rc = RegSetValueExW(hLinkageKey, L"UpperBind", 0, REG_SZ, (const BYTE*)L"Tcpip", (wcslen(L"Tcpip") + 1) * sizeof(WCHAR));
274 if (rc != ERROR_SUCCESS)
275 {
276 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
277 goto cleanup;
278 }
279 RegCloseKey(hKey);
280 hKey = INVALID_HANDLE_VALUE;
281
282 /* Write connection information in network subkey */
283 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hNetworkKey, NULL);
284 if (rc != ERROR_SUCCESS)
285 {
286 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
287 goto cleanup;
288 }
289 rc = RegCreateKeyExW(hNetworkKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hKey, NULL);
290 if (rc != ERROR_SUCCESS)
291 {
292 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
293 goto cleanup;
294 }
295 rc = RegCreateKeyExW(hKey, L"Connection", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hConnectionKey, NULL);
296 RegCloseKey(hKey);
297 hKey = INVALID_HANDLE_VALUE;
298 if (rc != ERROR_SUCCESS)
299 {
300 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
301 goto cleanup;
302 }
303 rc = RegSetValueExW(hConnectionKey, L"Name", 0, REG_SZ, (const BYTE*)L"Network connection", (wcslen(L"Network connection") + 1) * sizeof(WCHAR));
304 if (rc != ERROR_SUCCESS)
305 {
306 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
307 goto cleanup;
308 }
309 rc = RegSetValueExW(hConnectionKey, L"PnpInstanceId", 0, REG_SZ, (const BYTE*)InstanceId, (wcslen(InstanceId) + 1) * sizeof(WCHAR));
310 if (rc != ERROR_SUCCESS)
311 {
312 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
313 goto cleanup;
314 }
315 dwShowIcon = 1;
316 rc = RegSetValueExW(hConnectionKey, L"ShowIcon", 0, REG_DWORD, (const BYTE*)&dwShowIcon, sizeof(dwShowIcon));
317 if (rc != ERROR_SUCCESS)
318 {
319 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
320 goto cleanup;
321 }
322
323 /* Write linkage information in Tcpip service */
324 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hKey, NULL);
325 if (rc != ERROR_SUCCESS)
326 {
327 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
328 goto cleanup;
329 }
330 rc = AppendStringToMultiSZ(hKey, L"Bind", DeviceName);
331 if (rc != ERROR_SUCCESS)
332 {
333 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
334 goto cleanup;
335 }
336 rc = AppendStringToMultiSZ(hKey, L"Export", ExportName);
337 if (rc != ERROR_SUCCESS)
338 {
339 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
340 goto cleanup;
341 }
342 rc = AppendStringToMultiSZ(hKey, L"Route", UuidString);
343 if (rc != ERROR_SUCCESS)
344 {
345 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
346 goto cleanup;
347 }
348
349 /* HACK: hpoussin, Dec 2005. TCP/IP driver is not able to manage devices
350 * which are installed after its startup. So, we have to reboot to take
351 * this new netcard into account.
352 */
353 MessageBox(NULL, TEXT("You need to reboot to finish the installation of your network card."), TEXT("Reboot required"), MB_OK | MB_ICONWARNING);
354 rc = ERROR_SUCCESS;
355
356 cleanup:
357 if (UuidRpcString != NULL)
358 RpcStringFreeW(&UuidRpcString);
359 HeapFree(GetProcessHeap(), 0, InstanceId);
360 HeapFree(GetProcessHeap(), 0, UuidString);
361 HeapFree(GetProcessHeap(), 0, DeviceName);
362 HeapFree(GetProcessHeap(), 0, ExportName);
363 if (hKey != INVALID_HANDLE_VALUE)
364 RegCloseKey(hKey);
365 if (hLinkageKey != INVALID_HANDLE_VALUE)
366 RegCloseKey(hLinkageKey);
367 if (hNetworkKey != INVALID_HANDLE_VALUE)
368 RegCloseKey(hNetworkKey);
369 if (hConnectionKey != INVALID_HANDLE_VALUE)
370 RegCloseKey(hConnectionKey);
371
372 if (rc == ERROR_SUCCESS)
373 rc = ERROR_DI_DO_DEFAULT;
374 DPRINT("Returning 0x%lx\n", rc);
375 return rc;
376 }