xref: /reactos/dll/win32/netcfgx/installer.c (revision 7b970c67)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Configuration of network devices
4  * FILE:            dll/win32/netcfgx/installer.c
5  * PURPOSE:         Network devices installer
6  *
7  * PROGRAMMERS:     Hervé Poussineau (hpoussin@reactos.org)
8  */
9 
10 #include "precomp.h"
11 #include <strsafe.h>
12 
13 
14 /* Append a REG_SZ to an existing REG_MULTI_SZ string in the registry.
15  * If the value doesn't exist, create it.
16  * Returns ERROR_SUCCESS if success. Otherwise, returns an error code
17  */
18 static
19 LONG
AppendStringToMultiSZ(IN HKEY hKey,IN PCWSTR ValueName,IN PCWSTR ValueToAppend)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(hKey,
32                           ValueName,
33                           NULL,
34                           &dwRegType,
35                           NULL,
36                           &dwRequired);
37     if (rc != ERROR_FILE_NOT_FOUND)
38     {
39         if (rc != ERROR_SUCCESS)
40             goto cleanup;
41         if (dwRegType != REG_MULTI_SZ)
42         {
43             rc = ERROR_GEN_FAILURE;
44             goto cleanup;
45         }
46 
47         dwTmp = dwLength = dwRequired + wcslen(ValueToAppend) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
48         Buffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
49         if (!Buffer)
50         {
51             rc = ERROR_NOT_ENOUGH_MEMORY;
52             goto cleanup;
53         }
54 
55         rc = RegQueryValueExW(hKey,
56                               ValueName,
57                               NULL,
58                               NULL,
59                               (BYTE*)Buffer,
60                               &dwTmp);
61         if (rc != ERROR_SUCCESS)
62             goto cleanup;
63     }
64     else
65     {
66         dwRequired = sizeof(WCHAR);
67         dwLength = wcslen(ValueToAppend) * sizeof(WCHAR) + 2 * sizeof(UNICODE_NULL);
68         Buffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
69         if (!Buffer)
70         {
71             rc = ERROR_NOT_ENOUGH_MEMORY;
72             goto cleanup;
73         }
74     }
75 
76     /* Append the value */
77     wcscpy(&Buffer[dwRequired / sizeof(WCHAR) - 1], ValueToAppend);
78     /* Terminate the REG_MULTI_SZ string */
79     Buffer[dwLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
80 
81     rc = RegSetValueExW(hKey,
82                         ValueName,
83                         0,
84                         REG_MULTI_SZ,
85                         (const BYTE*)Buffer,
86                         dwLength);
87 
88 cleanup:
89     HeapFree(GetProcessHeap(), 0, Buffer);
90     return rc;
91 }
92 
93 static
94 DWORD
GetUniqueConnectionName(_In_ HKEY hNetworkKey,_Out_ PWSTR * ppszNameBuffer)95 GetUniqueConnectionName(
96     _In_ HKEY hNetworkKey,
97     _Out_ PWSTR *ppszNameBuffer)
98 {
99     int Length = 0;
100     PWSTR pszDefaultName = NULL;
101     PWSTR pszNameBuffer = NULL;
102     DWORD dwSubKeys = 0;
103     DWORD dwError;
104 
105     TRACE("GetNewConnectionName()\n");
106 
107     Length = LoadStringW(netcfgx_hInstance, IDS_NET_CONNECT, (LPWSTR)&pszDefaultName, 0);
108     if (Length == 0)
109     {
110         pszDefaultName = L"Network Connection";
111         Length = wcslen(pszDefaultName);
112     }
113 
114     TRACE("Length %d\n", Length);
115 
116     dwError = RegQueryInfoKeyW(hNetworkKey,
117                                NULL, NULL, NULL, &dwSubKeys,
118                                NULL, NULL, NULL, NULL, NULL, NULL, NULL);
119     if (dwError != ERROR_SUCCESS)
120     {
121         ERR("RegQueryInfoKeyW: Error %lu\n", dwError);
122         return dwError;
123     }
124 
125     TRACE("Adapter Count: %lu\n", dwSubKeys);
126 
127     pszNameBuffer = HeapAlloc(GetProcessHeap(),
128                               HEAP_ZERO_MEMORY,
129                               (Length + ((dwSubKeys != 0) ? 6 : 1)) * sizeof(WCHAR));
130     if (pszNameBuffer == NULL)
131     {
132         return ERROR_OUTOFMEMORY;
133     }
134 
135     if (dwSubKeys != 0)
136         StringCchPrintfW(pszNameBuffer, Length + 6, L"%.*s %lu", Length, pszDefaultName, dwSubKeys + 1);
137     else
138         StringCchPrintfW(pszNameBuffer, Length + 1, L"%.*s", Length, pszDefaultName);
139 
140     TRACE("Adapter Name: %S\n", pszNameBuffer);
141 
142     *ppszNameBuffer = pszNameBuffer;
143 
144     return ERROR_SUCCESS;
145 }
146 
147 static
148 DWORD
InstallNetDevice(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,LPCWSTR UuidString,DWORD Characteristics,LPCWSTR BusType)149 InstallNetDevice(
150     IN HDEVINFO DeviceInfoSet,
151     IN PSP_DEVINFO_DATA DeviceInfoData,
152     LPCWSTR UuidString,
153     DWORD Characteristics,
154     LPCWSTR BusType)
155 {
156     SP_DEVINSTALL_PARAMS_W DeviceInstallParams;
157     LPWSTR InstanceId = NULL;
158     LPWSTR ComponentId = NULL;
159     LPWSTR DeviceName = NULL;
160     LPWSTR ExportName = NULL;
161     LONG rc;
162     HKEY hKey = NULL;
163     HKEY hNetworkKey = NULL;
164     HKEY hLinkageKey = NULL;
165     HKEY hConnectionKey = NULL;
166     DWORD dwShowIcon, dwLength, dwValue;
167     PWSTR pszNameBuffer = NULL;
168     PWSTR ptr;
169 
170     DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
171     if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
172                                         DeviceInfoData,
173                                         &DeviceInstallParams))
174     {
175         rc = GetLastError();
176         ERR("SetupDiGetDeviceInstallParamsW() failed (Error %lu)\n", rc);
177         goto cleanup;
178     }
179 
180     /* Do not start the adapter in the call to SetupDiInstallDevice */
181     DeviceInstallParams.Flags |= DI_DONOTCALLCONFIGMG;
182 
183     if (!SetupDiSetDeviceInstallParamsW(DeviceInfoSet,
184                                         DeviceInfoData,
185                                         &DeviceInstallParams))
186     {
187         rc = GetLastError();
188         ERR("SetupDiSetDeviceInstallParamsW() failed (Error %lu)\n", rc);
189         goto cleanup;
190     }
191 
192     /* Install the adapter */
193     if (!SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData))
194     {
195         rc = GetLastError();
196         ERR("SetupDiInstallDevice() failed (Error %lu)\n", rc);
197         goto cleanup;
198     }
199 
200     /* Get Instance ID */
201     if (SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, NULL, 0, &dwLength))
202     {
203         ERR("SetupDiGetDeviceInstanceIdW() returned TRUE. FALSE expected\n");
204         rc = ERROR_GEN_FAILURE;
205         goto cleanup;
206     }
207 
208     InstanceId = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
209     if (!InstanceId)
210     {
211         ERR("HeapAlloc() failed\n");
212         rc = ERROR_NOT_ENOUGH_MEMORY;
213         goto cleanup;
214     }
215 
216     if (!SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, InstanceId, dwLength, NULL))
217     {
218         rc = GetLastError();
219         ERR("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", rc);
220         goto cleanup;
221     }
222 
223     ComponentId = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
224     if (!ComponentId)
225     {
226         ERR("HeapAlloc() failed\n");
227         rc = ERROR_NOT_ENOUGH_MEMORY;
228         goto cleanup;
229     }
230 
231     wcscpy(ComponentId, InstanceId);
232     ptr = wcsrchr(ComponentId, L'\\');
233     if (ptr != NULL)
234         *ptr = UNICODE_NULL;
235 
236     /* Create device name */
237     DeviceName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
238     if (!DeviceName)
239     {
240         ERR("HeapAlloc() failed\n");
241         rc = ERROR_NOT_ENOUGH_MEMORY;
242         goto cleanup;
243     }
244     wcscpy(DeviceName, L"\\Device\\");
245     wcscat(DeviceName, UuidString);
246 
247     /* Create export name */
248     ExportName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\Tcpip_") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
249     if (!ExportName)
250     {
251         ERR("HeapAlloc() failed\n");
252         rc = ERROR_NOT_ENOUGH_MEMORY;
253         goto cleanup;
254     }
255     wcscpy(ExportName, L"\\Device\\Tcpip_");
256     wcscat(ExportName, UuidString);
257 
258     /* Write Tcpip parameters in new service Key */
259     rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hKey, NULL);
260     if (rc != ERROR_SUCCESS)
261     {
262         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
263         goto cleanup;
264     }
265 
266     rc = RegCreateKeyExW(hKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hNetworkKey, NULL);
267     if (rc != ERROR_SUCCESS)
268     {
269         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
270         goto cleanup;
271     }
272     RegCloseKey(hKey);
273     hKey = NULL;
274 
275     rc = RegCreateKeyExW(hNetworkKey, L"Parameters\\Tcpip", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL);
276     if (rc != ERROR_SUCCESS)
277     {
278         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
279         goto cleanup;
280     }
281     RegCloseKey(hNetworkKey);
282     hNetworkKey = NULL;
283 
284     rc = RegSetValueExW(hKey, L"DefaultGateway", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
285     if (rc != ERROR_SUCCESS)
286     {
287         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
288         goto cleanup;
289     }
290 
291     rc = RegSetValueExW(hKey, L"IPAddress", 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         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
295         goto cleanup;
296     }
297 
298     rc = RegSetValueExW(hKey, L"SubnetMask", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
299     if (rc != ERROR_SUCCESS)
300     {
301         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
302         goto cleanup;
303     }
304 
305     dwValue = 1;
306     rc = RegSetValueExW(hKey, L"EnableDHCP", 0, REG_DWORD, (const BYTE*)&dwValue, sizeof(DWORD));
307     if (rc != ERROR_SUCCESS)
308     {
309         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
310         goto cleanup;
311     }
312     RegCloseKey(hKey);
313     hKey = NULL;
314 
315     /* Write 'Linkage' key in hardware key */
316 #if _WIN32_WINNT >= 0x502
317     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
318 #else
319     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
320 #endif
321     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
322         hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
323     if (hKey == INVALID_HANDLE_VALUE)
324     {
325         hKey = NULL;
326         rc = GetLastError();
327         ERR("SetupDiCreateDevRegKeyW() failed with error 0x%lx\n", rc);
328         goto cleanup;
329     }
330 
331     rc = RegSetValueExW(hKey, L"NetCfgInstanceId", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
332     if (rc != ERROR_SUCCESS)
333     {
334         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
335         goto cleanup;
336     }
337 
338     rc = RegSetValueExW(hKey, L"Characteristics", 0, REG_DWORD, (const BYTE*)&Characteristics, sizeof(DWORD));
339     if (rc != ERROR_SUCCESS)
340     {
341         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
342         goto cleanup;
343     }
344 
345     rc = RegSetValueExW(hKey, L"ComponentId", 0, REG_SZ, (const BYTE*)ComponentId, (wcslen(ComponentId) + 1) * sizeof(WCHAR));
346     if (rc != ERROR_SUCCESS)
347     {
348         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
349         goto cleanup;
350     }
351 
352     if (BusType)
353     {
354         rc = RegSetValueExW(hKey, L"BusType", 0, REG_SZ, (const BYTE*)BusType, (wcslen(BusType) + 1) * sizeof(WCHAR));
355         if (rc != ERROR_SUCCESS)
356         {
357             ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
358             goto cleanup;
359         }
360     }
361 
362     rc = RegCreateKeyExW(hKey, L"Linkage", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hLinkageKey, NULL);
363     if (rc != ERROR_SUCCESS)
364     {
365         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
366         goto cleanup;
367     }
368 
369     rc = RegSetValueExW(hLinkageKey, L"Export", 0, REG_SZ, (const BYTE*)DeviceName, (wcslen(DeviceName) + 1) * sizeof(WCHAR));
370     if (rc != ERROR_SUCCESS)
371     {
372         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
373         goto cleanup;
374     }
375 
376     rc = RegSetValueExW(hLinkageKey, L"RootDevice", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
377     if (rc != ERROR_SUCCESS)
378     {
379         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
380         goto cleanup;
381     }
382 
383     rc = RegSetValueExW(hLinkageKey, L"UpperBind", 0, REG_SZ, (const BYTE*)L"Tcpip", (wcslen(L"Tcpip") + 1) * sizeof(WCHAR));
384     if (rc != ERROR_SUCCESS)
385     {
386         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
387         goto cleanup;
388     }
389     RegCloseKey(hKey);
390     hKey = NULL;
391 
392     /* Write connection information in network subkey */
393     rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
394                          L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
395                          0,
396                          NULL,
397                          REG_OPTION_NON_VOLATILE,
398                          KEY_CREATE_SUB_KEY | KEY_QUERY_VALUE,
399                          NULL,
400                          &hNetworkKey,
401                          NULL);
402     if (rc != ERROR_SUCCESS)
403     {
404         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
405         goto cleanup;
406     }
407 
408     rc = GetUniqueConnectionName(hNetworkKey, &pszNameBuffer);
409     if (rc != ERROR_SUCCESS)
410     {
411         ERR("GetUniqueConnectionName() failed with error 0x%lx\n", rc);
412         goto cleanup;
413     }
414 
415     rc = RegCreateKeyExW(hNetworkKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hKey, NULL);
416     if (rc != ERROR_SUCCESS)
417     {
418         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
419         goto cleanup;
420     }
421 
422     rc = RegCreateKeyExW(hKey, L"Connection", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hConnectionKey, NULL);
423     RegCloseKey(hKey);
424     hKey = NULL;
425     if (rc != ERROR_SUCCESS)
426     {
427         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
428         goto cleanup;
429     }
430 
431     rc = RegSetValueExW(hConnectionKey, L"Name", 0, REG_SZ, (const BYTE*)pszNameBuffer, (wcslen(pszNameBuffer) + 1) * sizeof(WCHAR));
432     if (rc != ERROR_SUCCESS)
433     {
434         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
435         goto cleanup;
436     }
437 
438     rc = RegSetValueExW(hConnectionKey, L"PnpInstanceID", 0, REG_SZ, (const BYTE*)InstanceId, (wcslen(InstanceId) + 1) * sizeof(WCHAR));
439     if (rc != ERROR_SUCCESS)
440     {
441         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
442         goto cleanup;
443     }
444 
445     dwShowIcon = 1;
446     rc = RegSetValueExW(hConnectionKey, L"ShowIcon", 0, REG_DWORD, (const BYTE*)&dwShowIcon, sizeof(dwShowIcon));
447     if (rc != ERROR_SUCCESS)
448     {
449         ERR("RegSetValueExW() failed with error 0x%lx\n", rc);
450         goto cleanup;
451     }
452 
453     /* Write linkage information in Tcpip service */
454     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);
455     if (rc != ERROR_SUCCESS)
456     {
457         ERR("RegCreateKeyExW() failed with error 0x%lx\n", rc);
458         goto cleanup;
459     }
460     rc = AppendStringToMultiSZ(hKey, L"Bind", DeviceName);
461     if (rc != ERROR_SUCCESS)
462     {
463         ERR("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
464         goto cleanup;
465     }
466     rc = AppendStringToMultiSZ(hKey, L"Export", ExportName);
467     if (rc != ERROR_SUCCESS)
468     {
469         ERR("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
470         goto cleanup;
471     }
472     rc = AppendStringToMultiSZ(hKey, L"Route", UuidString);
473     if (rc != ERROR_SUCCESS)
474     {
475         ERR("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
476         goto cleanup;
477     }
478 
479     /* Start the device */
480     if (!SetupDiRestartDevices(DeviceInfoSet, DeviceInfoData))
481     {
482         rc = GetLastError();
483         ERR("SetupDiRestartDevices() failed with error 0x%lx\n", rc);
484         goto cleanup;
485     }
486 
487     rc = ERROR_SUCCESS;
488 
489 cleanup:
490     HeapFree(GetProcessHeap(), 0, pszNameBuffer);
491     HeapFree(GetProcessHeap(), 0, InstanceId);
492     HeapFree(GetProcessHeap(), 0, ComponentId);
493     HeapFree(GetProcessHeap(), 0, DeviceName);
494     HeapFree(GetProcessHeap(), 0, ExportName);
495     if (hKey != NULL)
496         RegCloseKey(hKey);
497     if (hNetworkKey != NULL)
498         RegCloseKey(hNetworkKey);
499     if (hLinkageKey != NULL)
500         RegCloseKey(hLinkageKey);
501     if (hConnectionKey != NULL)
502         RegCloseKey(hConnectionKey);
503 
504     return rc;
505 }
506 
507 static
508 DWORD
InstallNetClient(VOID)509 InstallNetClient(VOID)
510 {
511     FIXME("Installation of network clients is not yet supported\n");
512     return ERROR_GEN_FAILURE;
513 }
514 
515 static
516 DWORD
InstallNetService(VOID)517 InstallNetService(VOID)
518 {
519     FIXME("Installation of network services is not yet supported\n");
520     return ERROR_GEN_FAILURE;
521 }
522 
523 static
524 DWORD
InstallNetTransport(VOID)525 InstallNetTransport(VOID)
526 {
527     FIXME("Installation of network protocols is not yet supported\n");
528     return ERROR_GEN_FAILURE;
529 }
530 
531 DWORD
532 WINAPI
NetClassInstaller(IN DI_FUNCTION InstallFunction,IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)533 NetClassInstaller(
534     IN DI_FUNCTION InstallFunction,
535     IN HDEVINFO DeviceInfoSet,
536     IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
537 {
538     SP_DRVINFO_DATA_W DriverInfoData;
539     SP_DRVINFO_DETAIL_DATA_W DriverInfoDetail;
540     WCHAR SectionName[LINE_LEN];
541     HINF hInf = INVALID_HANDLE_VALUE;
542     INFCONTEXT InfContext;
543     UINT ErrorLine;
544     INT CharacteristicsInt;
545     DWORD Characteristics;
546     LPWSTR BusType = NULL;
547     RPC_STATUS RpcStatus;
548     UUID Uuid;
549     LPWSTR UuidRpcString = NULL;
550     LPWSTR UuidString = NULL;
551     LONG rc;
552     DWORD dwLength;
553 
554     if (InstallFunction != DIF_INSTALLDEVICE)
555         return ERROR_DI_DO_DEFAULT;
556 
557     TRACE("%lu %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
558 
559     /* Get driver info details */
560     DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
561     if (!SetupDiGetSelectedDriverW(DeviceInfoSet, DeviceInfoData, &DriverInfoData))
562     {
563         rc = GetLastError();
564         ERR("SetupDiGetSelectedDriverW() failed with error 0x%lx\n", rc);
565         goto cleanup;
566     }
567 
568     DriverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
569     if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet, DeviceInfoData, &DriverInfoData, &DriverInfoDetail, sizeof(DriverInfoDetail), NULL)
570      && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
571     {
572         rc = GetLastError();
573         ERR("SetupDiGetDriverInfoDetailW() failed with error 0x%lx\n", rc);
574         goto cleanup;
575     }
576 
577     hInf = SetupOpenInfFileW(DriverInfoDetail.InfFileName, NULL, INF_STYLE_WIN4, &ErrorLine);
578     if (hInf == INVALID_HANDLE_VALUE)
579     {
580         rc = GetLastError();
581         ERR("SetupOpenInfFileW() failed with error 0x%lx\n", rc);
582         goto cleanup;
583     }
584 
585     if (!SetupDiGetActualSectionToInstallW(hInf, DriverInfoDetail.SectionName, SectionName, LINE_LEN, NULL, NULL))
586     {
587         rc = GetLastError();
588         ERR("SetupDiGetActualSectionToInstallW() failed with error 0x%lx\n", rc);
589         goto cleanup;
590     }
591 
592     /* Get Characteristics and BusType (optional) from .inf file */
593     if (!SetupFindFirstLineW(hInf, SectionName, L"Characteristics", &InfContext))
594     {
595         rc = GetLastError();
596         ERR("Unable to find key %S in section %S of file %S (error 0x%lx)\n",
597             L"Characteristics", SectionName, DriverInfoDetail.InfFileName, rc);
598         goto cleanup;
599     }
600 
601     if (!SetupGetIntField(&InfContext, 1, &CharacteristicsInt))
602     {
603         rc = GetLastError();
604         ERR("SetupGetIntField() failed with error 0x%lx\n", rc);
605         goto cleanup;
606     }
607 
608     Characteristics = (DWORD)CharacteristicsInt;
609     if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
610     {
611         if (SetupFindFirstLineW(hInf, SectionName, L"BusType", &InfContext))
612         {
613             if (!SetupGetStringFieldW(&InfContext, 1, NULL, 0, &dwLength))
614             {
615                 rc = GetLastError();
616                 ERR("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
617                 goto cleanup;
618             }
619 
620             BusType = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
621             if (!BusType)
622             {
623                 ERR("HeapAlloc() failed\n");
624                 rc = ERROR_NOT_ENOUGH_MEMORY;
625                 goto cleanup;
626             }
627 
628             if (!SetupGetStringFieldW(&InfContext, 1, BusType, dwLength, NULL))
629             {
630                 rc = GetLastError();
631                 ERR("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
632                 goto cleanup;
633             }
634         }
635     }
636 
637     /* Create a new UUID */
638     RpcStatus = UuidCreate(&Uuid);
639     if (RpcStatus != RPC_S_OK && RpcStatus != RPC_S_UUID_LOCAL_ONLY)
640     {
641         ERR("UuidCreate() failed with RPC status 0x%lx\n", RpcStatus);
642         rc = ERROR_GEN_FAILURE;
643         goto cleanup;
644     }
645 
646     RpcStatus = UuidToStringW(&Uuid, &UuidRpcString);
647     if (RpcStatus != RPC_S_OK)
648     {
649         ERR("UuidToStringW() failed with RPC status 0x%lx\n", RpcStatus);
650         rc = ERROR_GEN_FAILURE;
651         goto cleanup;
652     }
653 
654     /* Add curly braces around Uuid */
655     UuidString = HeapAlloc(GetProcessHeap(), 0, (2 + wcslen(UuidRpcString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
656     if (!UuidString)
657     {
658         ERR("HeapAlloc() failed\n");
659         rc = ERROR_NOT_ENOUGH_MEMORY;
660         goto cleanup;
661     }
662 
663     wcscpy(UuidString, L"{");
664     wcscat(UuidString, UuidRpcString);
665     wcscat(UuidString, L"}");
666 
667     if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
668         rc = InstallNetDevice(DeviceInfoSet, DeviceInfoData, UuidString, Characteristics, BusType);
669     else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETCLIENT))
670         rc = InstallNetClient();
671     else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETSERVICE))
672         rc = InstallNetService();
673     else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETTRANS))
674         rc = InstallNetTransport();
675     else
676     {
677         ERR("Invalid class guid\n");
678         rc = ERROR_GEN_FAILURE;
679     }
680 
681 cleanup:
682     if (hInf != INVALID_HANDLE_VALUE)
683         SetupCloseInfFile(hInf);
684     if (UuidRpcString != NULL)
685         RpcStringFreeW(&UuidRpcString);
686     HeapFree(GetProcessHeap(), 0, BusType);
687     HeapFree(GetProcessHeap(), 0, UuidString);
688 
689     TRACE("Returning 0x%lx\n", rc);
690     return rc;
691 }
692