First step to automatically generate registry entries for network protocols (TcpIp...)
[reactos.git] / reactos / dll / win32 / 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 /* Install a section of a .inf file
96 * Returns TRUE if success, FALSE if failure. Error code can
97 * be retrieved with GetLastError()
98 */
99 static BOOL
100 InstallInfSection(
101 IN HWND hWnd,
102 IN LPCWSTR InfFile,
103 IN LPCWSTR InfSection)
104 {
105 WCHAR Buffer[MAX_PATH];
106 HINF hInf = INVALID_HANDLE_VALUE;
107 UINT BufferSize;
108 PVOID Context = NULL;
109 BOOL ret = FALSE;
110
111 /* Get Windows directory */
112 BufferSize = MAX_PATH - 5 - wcslen(InfFile);
113 if (GetWindowsDirectoryW(Buffer, BufferSize) > BufferSize)
114 {
115 /* Function failed */
116 SetLastError(ERROR_GEN_FAILURE);
117 goto cleanup;
118 }
119 /* We have enough space to add some information in the buffer */
120 if (Buffer[wcslen(Buffer) - 1] != '\\')
121 wcscat(Buffer, L"\\");
122 wcscat(Buffer, L"Inf\\");
123 wcscat(Buffer, InfFile);
124
125 /* Install specified section */
126 hInf = SetupOpenInfFileW(Buffer, NULL, INF_STYLE_WIN4, NULL);
127 if (hInf == INVALID_HANDLE_VALUE)
128 goto cleanup;
129
130 Context = SetupInitDefaultQueueCallback(hWnd);
131 if (Context == NULL)
132 goto cleanup;
133
134 ret = SetupInstallFromInfSectionW(
135 hWnd, hInf,
136 InfSection, SPINST_ALL,
137 NULL, NULL, SP_COPY_NEWER,
138 SetupDefaultQueueCallbackW, Context,
139 NULL, NULL);
140
141 cleanup:
142 if (Context)
143 SetupTermDefaultQueueCallback(Context);
144 if (hInf != INVALID_HANDLE_VALUE)
145 SetupCloseInfFile(hInf);
146 return ret;
147 }
148
149 /* Add default services for network cards */
150 static DWORD
151 InstallAdditionalServices(
152 IN HWND hWnd)
153 {
154 BOOL ret;
155
156 /* Install TCP/IP protocol */
157 ret = InstallInfSection(
158 hWnd,
159 L"nettcpip.inf",
160 L"MS_TCPIP.PrimaryInstall");
161 if (!ret && GetLastError() != ERROR_FILE_NOT_FOUND)
162 {
163 DPRINT("InstallInfSection() failed with error 0x%lx\n", GetLastError());
164 return GetLastError();
165 }
166
167 /* You can add here more clients (SMB...) and services (DHCP server...) */
168
169 return ERROR_SUCCESS;
170 }
171
172 DWORD WINAPI
173 NetClassInstaller(
174 IN DI_FUNCTION InstallFunction,
175 IN HDEVINFO DeviceInfoSet,
176 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
177 {
178 RPC_STATUS RpcStatus;
179 UUID Uuid;
180 LPWSTR InstanceId = NULL;
181 LPWSTR UuidRpcString = NULL;
182 LPWSTR UuidString = NULL;
183 LPWSTR DeviceName = NULL;
184 LPWSTR ExportName = NULL;
185 LONG rc;
186 DWORD dwShowIcon, dwLength;
187 HKEY hKey = INVALID_HANDLE_VALUE;
188 HKEY hLinkageKey = INVALID_HANDLE_VALUE;
189 HKEY hNetworkKey = INVALID_HANDLE_VALUE;
190 HKEY hConnectionKey = INVALID_HANDLE_VALUE;
191
192 if (InstallFunction != DIF_INSTALLDEVICE)
193 return ERROR_DI_DO_DEFAULT;
194
195 DPRINT("%lu %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
196
197 /* Get Instance ID */
198 if (SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, NULL, 0, &dwLength))
199 {
200 DPRINT("SetupDiGetDeviceInstanceIdW() returned TRUE. FALSE expected\n");
201 rc = ERROR_GEN_FAILURE;
202 goto cleanup;
203 }
204 InstanceId = HeapAlloc(GetProcessHeap(), 0, dwLength);
205 if (!InstanceId)
206 {
207 DPRINT("HeapAlloc() failed\n");
208 rc = ERROR_NOT_ENOUGH_MEMORY;
209 goto cleanup;
210 }
211 if (!SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, InstanceId, dwLength, NULL))
212 {
213 rc = GetLastError();
214 DPRINT("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", rc);
215 goto cleanup;
216 }
217
218 /* Create a new UUID */
219 RpcStatus = UuidCreate(&Uuid);
220 if (RpcStatus != RPC_S_OK && RpcStatus != RPC_S_UUID_LOCAL_ONLY)
221 {
222 DPRINT("UuidCreate() failed with RPC status 0x%lx\n", RpcStatus);
223 rc = ERROR_GEN_FAILURE;
224 goto cleanup;
225 }
226 RpcStatus = UuidToStringW(&Uuid, &UuidRpcString);
227 if (RpcStatus != RPC_S_OK)
228 {
229 DPRINT("UuidToStringW() failed with RPC status 0x%lx\n", RpcStatus);
230 rc = ERROR_GEN_FAILURE;
231 goto cleanup;
232 }
233
234 /* Add curly braces around Uuid */
235 UuidString = HeapAlloc(GetProcessHeap(), 0, (2 + wcslen(UuidRpcString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
236 if (!UuidString)
237 {
238 DPRINT("HeapAlloc() failed\n");
239 rc = ERROR_NOT_ENOUGH_MEMORY;
240 goto cleanup;
241 }
242 wcscpy(UuidString, L"{");
243 wcscat(UuidString, UuidRpcString);
244 wcscat(UuidString, L"}");
245
246 /* Create device name */
247 DeviceName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
248 if (!DeviceName)
249 {
250 DPRINT("HeapAlloc() failed\n");
251 rc = ERROR_NOT_ENOUGH_MEMORY;
252 goto cleanup;
253 }
254 wcscpy(DeviceName, L"\\Device\\");
255 wcscat(DeviceName, UuidString);
256
257 /* Create export name */
258 ExportName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\Tcpip_") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
259 if (!ExportName)
260 {
261 DPRINT("HeapAlloc() failed\n");
262 rc = ERROR_NOT_ENOUGH_MEMORY;
263 goto cleanup;
264 }
265 wcscpy(ExportName, L"\\Device\\Tcpip_");
266 wcscat(ExportName, UuidString);
267
268 /* Write Tcpip parameters in new service Key */
269 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services", 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hKey, NULL);
270 if (rc != ERROR_SUCCESS)
271 {
272 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
273 goto cleanup;
274 }
275 rc = RegCreateKeyExW(hKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hNetworkKey, NULL);
276 if (rc != ERROR_SUCCESS)
277 {
278 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
279 goto cleanup;
280 }
281 RegCloseKey(hKey);
282 hKey = INVALID_HANDLE_VALUE;
283 rc = RegCreateKeyExW(hNetworkKey, L"Parameters\\Tcpip", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL);
284 if (rc != ERROR_SUCCESS)
285 {
286 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
287 goto cleanup;
288 }
289 RegCloseKey(hNetworkKey);
290 hNetworkKey = INVALID_HANDLE_VALUE;
291 rc = RegSetValueExW(hKey, L"DefaultGateway", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
292 if (rc != ERROR_SUCCESS)
293 {
294 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
295 goto cleanup;
296 }
297 rc = RegSetValueExW(hKey, L"IPAddress", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
298 if (rc != ERROR_SUCCESS)
299 {
300 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
301 goto cleanup;
302 }
303 rc = RegSetValueExW(hKey, L"SubnetMask", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
304 if (rc != ERROR_SUCCESS)
305 {
306 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
307 goto cleanup;
308 }
309 RegCloseKey(hKey);
310 hKey = INVALID_HANDLE_VALUE;
311
312 /* Write 'Linkage' key in hardware key */
313 #if _WIN32_WINNT >= 0x502
314 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
315 #else
316 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
317 #endif
318 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
319 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
320 if (hKey == INVALID_HANDLE_VALUE)
321 {
322 rc = GetLastError();
323 DPRINT("SetupDiCreateDevRegKeyW() failed with error 0x%lx\n", rc);
324 goto cleanup;
325 }
326 rc = RegSetValueExW(hKey, L"NetCfgInstanceId", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
327 if (rc != ERROR_SUCCESS)
328 {
329 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
330 goto cleanup;
331 }
332 rc = RegCreateKeyExW(hKey, L"Linkage", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hLinkageKey, NULL);
333 if (rc != ERROR_SUCCESS)
334 {
335 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
336 goto cleanup;
337 }
338 rc = RegSetValueExW(hLinkageKey, L"Export", 0, REG_SZ, (const BYTE*)DeviceName, (wcslen(DeviceName) + 1) * sizeof(WCHAR));
339 if (rc != ERROR_SUCCESS)
340 {
341 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
342 goto cleanup;
343 }
344 rc = RegSetValueExW(hLinkageKey, L"RootDevice", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
345 if (rc != ERROR_SUCCESS)
346 {
347 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
348 goto cleanup;
349 }
350 rc = RegSetValueExW(hLinkageKey, L"UpperBind", 0, REG_SZ, (const BYTE*)L"Tcpip", (wcslen(L"Tcpip") + 1) * sizeof(WCHAR));
351 if (rc != ERROR_SUCCESS)
352 {
353 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
354 goto cleanup;
355 }
356 RegCloseKey(hKey);
357 hKey = INVALID_HANDLE_VALUE;
358
359 /* Write connection information in network subkey */
360 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);
361 if (rc != ERROR_SUCCESS)
362 {
363 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
364 goto cleanup;
365 }
366 rc = RegCreateKeyExW(hNetworkKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hKey, NULL);
367 if (rc != ERROR_SUCCESS)
368 {
369 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
370 goto cleanup;
371 }
372 rc = RegCreateKeyExW(hKey, L"Connection", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hConnectionKey, NULL);
373 RegCloseKey(hKey);
374 hKey = INVALID_HANDLE_VALUE;
375 if (rc != ERROR_SUCCESS)
376 {
377 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
378 goto cleanup;
379 }
380 rc = RegSetValueExW(hConnectionKey, L"Name", 0, REG_SZ, (const BYTE*)L"Network connection", (wcslen(L"Network connection") + 1) * sizeof(WCHAR));
381 if (rc != ERROR_SUCCESS)
382 {
383 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
384 goto cleanup;
385 }
386 rc = RegSetValueExW(hConnectionKey, L"PnpInstanceId", 0, REG_SZ, (const BYTE*)InstanceId, (wcslen(InstanceId) + 1) * sizeof(WCHAR));
387 if (rc != ERROR_SUCCESS)
388 {
389 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
390 goto cleanup;
391 }
392 dwShowIcon = 1;
393 rc = RegSetValueExW(hConnectionKey, L"ShowIcon", 0, REG_DWORD, (const BYTE*)&dwShowIcon, sizeof(dwShowIcon));
394 if (rc != ERROR_SUCCESS)
395 {
396 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
397 goto cleanup;
398 }
399
400 /* Write linkage information in Tcpip service */
401 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);
402 if (rc != ERROR_SUCCESS)
403 {
404 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
405 goto cleanup;
406 }
407 rc = AppendStringToMultiSZ(hKey, L"Bind", DeviceName);
408 if (rc != ERROR_SUCCESS)
409 {
410 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
411 goto cleanup;
412 }
413 rc = AppendStringToMultiSZ(hKey, L"Export", ExportName);
414 if (rc != ERROR_SUCCESS)
415 {
416 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
417 goto cleanup;
418 }
419 rc = AppendStringToMultiSZ(hKey, L"Route", UuidString);
420 if (rc != ERROR_SUCCESS)
421 {
422 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
423 goto cleanup;
424 }
425
426 /* Install additionnal services */
427 /* FIXME: do it only if it is a network adapter! */
428 rc = InstallAdditionalServices(NULL);
429 if (rc != ERROR_SUCCESS)
430 {
431 DPRINT("InstallAdditionalServices() failed with error 0x%lx\n", rc);
432 goto cleanup;
433 }
434
435 /* HACK: hpoussin, Dec 2005. TCP/IP driver is not able to manage devices
436 * which are installed after its startup. So, we have to reboot to take
437 * this new netcard into account.
438 */
439 MessageBox(NULL, TEXT("You need to reboot to finish the installation of your network card."), TEXT("Reboot required"), MB_OK | MB_ICONWARNING);
440 rc = ERROR_SUCCESS;
441
442 cleanup:
443 if (UuidRpcString != NULL)
444 RpcStringFreeW(&UuidRpcString);
445 HeapFree(GetProcessHeap(), 0, InstanceId);
446 HeapFree(GetProcessHeap(), 0, UuidString);
447 HeapFree(GetProcessHeap(), 0, DeviceName);
448 HeapFree(GetProcessHeap(), 0, ExportName);
449 if (hKey != INVALID_HANDLE_VALUE)
450 RegCloseKey(hKey);
451 if (hLinkageKey != INVALID_HANDLE_VALUE)
452 RegCloseKey(hLinkageKey);
453 if (hNetworkKey != INVALID_HANDLE_VALUE)
454 RegCloseKey(hNetworkKey);
455 if (hConnectionKey != INVALID_HANDLE_VALUE)
456 RegCloseKey(hConnectionKey);
457
458 if (rc == ERROR_SUCCESS)
459 rc = ERROR_DI_DO_DEFAULT;
460 DPRINT("Returning 0x%lx\n", rc);
461 return rc;
462 }