[NETCFGX]
[reactos.git] / reactos / dll / win32 / netcfgx / netcfgx.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Configuration of network devices
4 * FILE: dll/win32/netcfgx/netcfgx.c
5 * PURPOSE: Network devices installer
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10
11 #include "precomp.h"
12 #include <initguid.h>
13 #include <devguid.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 HINSTANCE netcfgx_hInstance;
18 const GUID CLSID_TcpipConfigNotifyObject = {0xA907657F, 0x6FDF, 0x11D0, {0x8E, 0xFB, 0x00, 0xC0, 0x4F, 0xD9, 0x12, 0xB2}};
19
20
21
22
23 static INTERFACE_TABLE InterfaceTable[] =
24 {
25 {
26 &CLSID_CNetCfg,
27 INetCfg_Constructor
28 },
29 {
30 &CLSID_TcpipConfigNotifyObject,
31 TcpipConfigNotify_Constructor
32 },
33 {
34 NULL,
35 NULL
36 }
37 };
38
39 BOOL
40 WINAPI
41 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
42 {
43 switch (fdwReason)
44 {
45 case DLL_PROCESS_ATTACH:
46 netcfgx_hInstance = hinstDLL;
47 DisableThreadLibraryCalls(netcfgx_hInstance);
48 break;
49 default:
50 break;
51 }
52
53 return TRUE;
54 }
55
56 HRESULT
57 WINAPI
58 DllCanUnloadNow(void)
59 {
60 return S_FALSE;
61 }
62
63 STDAPI
64 DllRegisterServer(void)
65 {
66 HKEY hKey, hSubKey;
67 LPOLESTR pStr;
68 WCHAR szName[MAX_PATH] = L"CLSID\\";
69
70 if (FAILED(StringFromCLSID(&CLSID_CNetCfg, &pStr)))
71 return SELFREG_E_CLASS;
72
73 wcscpy(&szName[6], pStr);
74 CoTaskMemFree(pStr);
75
76 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, szName, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
77 return SELFREG_E_CLASS;
78
79 if (RegCreateKeyExW(hKey, L"InProcServer32", 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
80 {
81 if (!GetModuleFileNameW(netcfgx_hInstance, szName, sizeof(szName)/sizeof(WCHAR)))
82 {
83 RegCloseKey(hSubKey);
84 RegCloseKey(hKey);
85 return SELFREG_E_CLASS;
86 }
87 szName[(sizeof(szName)/sizeof(WCHAR))-1] = L'\0';
88 RegSetValueW(hSubKey, NULL, REG_SZ, szName, (wcslen(szName)+1) * sizeof(WCHAR));
89 RegSetValueExW(hSubKey, L"ThreadingModel", 0, REG_SZ, (LPBYTE)L"Both", 10);
90 RegCloseKey(hSubKey);
91 }
92
93 RegCloseKey(hKey);
94 return S_OK;
95 }
96
97 STDAPI
98 DllUnregisterServer(void)
99 {
100 //FIXME
101 // implement unregistering services
102 //
103 return S_OK;
104 }
105
106 STDAPI
107 DllGetClassObject(
108 REFCLSID rclsid,
109 REFIID riid,
110 LPVOID* ppv
111 )
112 {
113 UINT i;
114 HRESULT hres = E_OUTOFMEMORY;
115 IClassFactory * pcf = NULL;
116
117 if (!ppv)
118 return E_INVALIDARG;
119
120 *ppv = NULL;
121
122 for (i = 0; InterfaceTable[i].riid; i++)
123 {
124 if (IsEqualIID(InterfaceTable[i].riid, rclsid))
125 {
126 pcf = IClassFactory_fnConstructor(InterfaceTable[i].lpfnCI, NULL, NULL);
127 break;
128 }
129 }
130
131 if (!pcf)
132 {
133 return CLASS_E_CLASSNOTAVAILABLE;
134 }
135
136 hres = IClassFactory_QueryInterface(pcf, riid, ppv);
137 IClassFactory_Release(pcf);
138
139 return hres;
140 }
141
142
143 /* Append a REG_SZ to an existing REG_MULTI_SZ string in the registry.
144 * If the value doesn't exist, create it.
145 * Returns ERROR_SUCCESS if success. Othewise, returns an error code
146 */
147 static LONG
148 AppendStringToMultiSZ(
149 IN HKEY hKey,
150 IN PCWSTR ValueName,
151 IN PCWSTR ValueToAppend)
152 {
153 PWSTR Buffer = NULL;
154 DWORD dwRegType;
155 DWORD dwRequired, dwLength;
156 DWORD dwTmp;
157 LONG rc;
158
159 rc = RegQueryValueExW(
160 hKey,
161 ValueName,
162 NULL,
163 &dwRegType,
164 NULL,
165 &dwRequired);
166 if (rc != ERROR_FILE_NOT_FOUND)
167 {
168 if (rc != ERROR_SUCCESS)
169 goto cleanup;
170 if (dwRegType != REG_MULTI_SZ)
171 {
172 rc = ERROR_GEN_FAILURE;
173 goto cleanup;
174 }
175
176 dwTmp = dwLength = dwRequired + wcslen(ValueToAppend) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
177 Buffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
178 if (!Buffer)
179 {
180 rc = ERROR_NOT_ENOUGH_MEMORY;
181 goto cleanup;
182 }
183 rc = RegQueryValueExW(
184 hKey,
185 ValueName,
186 NULL,
187 NULL,
188 (BYTE*)Buffer,
189 &dwTmp);
190 if (rc != ERROR_SUCCESS)
191 goto cleanup;
192 }
193 else
194 {
195 dwRequired = sizeof(WCHAR);
196 dwLength = wcslen(ValueToAppend) * sizeof(WCHAR) + 2 * sizeof(UNICODE_NULL);
197 Buffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
198 if (!Buffer)
199 {
200 rc = ERROR_NOT_ENOUGH_MEMORY;
201 goto cleanup;
202 }
203 }
204
205 /* Append the value */
206 wcscpy(&Buffer[dwRequired / sizeof(WCHAR) - 1], ValueToAppend);
207 /* Terminate the REG_MULTI_SZ string */
208 Buffer[dwLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
209
210 rc = RegSetValueExW(
211 hKey,
212 ValueName,
213 0,
214 REG_MULTI_SZ,
215 (const BYTE*)Buffer,
216 dwLength);
217
218 cleanup:
219 HeapFree(GetProcessHeap(), 0, Buffer);
220 return rc;
221 }
222
223 /* Install a section of a .inf file
224 * Returns TRUE if success, FALSE if failure. Error code can
225 * be retrieved with GetLastError()
226 */
227 static BOOL
228 InstallInfSection(
229 IN HWND hWnd,
230 IN LPCWSTR InfFile,
231 IN LPCWSTR InfSection OPTIONAL,
232 IN LPCWSTR InfService OPTIONAL)
233 {
234 WCHAR Buffer[MAX_PATH];
235 HINF hInf = INVALID_HANDLE_VALUE;
236 UINT BufferSize;
237 PVOID Context = NULL;
238 BOOL ret = FALSE;
239
240 /* Get Windows directory */
241 BufferSize = MAX_PATH - 5 - wcslen(InfFile);
242 if (GetWindowsDirectoryW(Buffer, BufferSize) > BufferSize)
243 {
244 /* Function failed */
245 SetLastError(ERROR_GEN_FAILURE);
246 goto cleanup;
247 }
248 /* We have enough space to add some information in the buffer */
249 if (Buffer[wcslen(Buffer) - 1] != '\\')
250 wcscat(Buffer, L"\\");
251 wcscat(Buffer, L"Inf\\");
252 wcscat(Buffer, InfFile);
253
254 /* Install specified section */
255 hInf = SetupOpenInfFileW(Buffer, NULL, INF_STYLE_WIN4, NULL);
256 if (hInf == INVALID_HANDLE_VALUE)
257 goto cleanup;
258
259 Context = SetupInitDefaultQueueCallback(hWnd);
260 if (Context == NULL)
261 goto cleanup;
262
263 ret = TRUE;
264 if (ret && InfSection)
265 {
266 ret = SetupInstallFromInfSectionW(
267 hWnd, hInf,
268 InfSection, SPINST_ALL,
269 NULL, NULL, SP_COPY_NEWER,
270 SetupDefaultQueueCallbackW, Context,
271 NULL, NULL);
272 }
273 if (ret && InfService)
274 {
275 ret = SetupInstallServicesFromInfSectionW(
276 hInf, InfService, 0);
277 }
278
279 cleanup:
280 if (Context)
281 SetupTermDefaultQueueCallback(Context);
282 if (hInf != INVALID_HANDLE_VALUE)
283 SetupCloseInfFile(hInf);
284 return ret;
285 }
286
287 /* Add default services for network cards */
288 static DWORD
289 InstallAdditionalServices(
290 IN HWND hWnd)
291 {
292 BOOL ret;
293
294 /* Install TCP/IP protocol */
295 ret = InstallInfSection(
296 hWnd,
297 L"nettcpip.inf",
298 L"MS_TCPIP.PrimaryInstall",
299 L"MS_TCPIP.PrimaryInstall.Services");
300 if (!ret && GetLastError() != ERROR_FILE_NOT_FOUND)
301 {
302 DPRINT("InstallInfSection() failed with error 0x%lx\n", GetLastError());
303 return GetLastError();
304 }
305
306 /* You can add here more clients (SMB...) and services (DHCP server...) */
307
308 return ERROR_SUCCESS;
309 }
310
311 static DWORD
312 InstallNetDevice(
313 IN HDEVINFO DeviceInfoSet,
314 IN PSP_DEVINFO_DATA DeviceInfoData,
315 LPCWSTR UuidString,
316 DWORD Characteristics,
317 LPCWSTR BusType)
318 {
319 LPWSTR InstanceId = NULL;
320 LPWSTR DeviceName = NULL;
321 LPWSTR ExportName = NULL;
322 LONG rc;
323 HKEY hKey = NULL;
324 HKEY hNetworkKey = NULL;
325 HKEY hLinkageKey = NULL;
326 HKEY hConnectionKey = NULL;
327 DWORD dwShowIcon, dwLength;
328
329 /* Get Instance ID */
330 if (SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, NULL, 0, &dwLength))
331 {
332 DPRINT("SetupDiGetDeviceInstanceIdW() returned TRUE. FALSE expected\n");
333 rc = ERROR_GEN_FAILURE;
334 goto cleanup;
335 }
336 InstanceId = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
337 if (!InstanceId)
338 {
339 DPRINT("HeapAlloc() failed\n");
340 rc = ERROR_NOT_ENOUGH_MEMORY;
341 goto cleanup;
342 }
343 if (!SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, InstanceId, dwLength, NULL))
344 {
345 rc = GetLastError();
346 DPRINT("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", rc);
347 goto cleanup;
348 }
349
350 /* Create device name */
351 DeviceName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
352 if (!DeviceName)
353 {
354 DPRINT("HeapAlloc() failed\n");
355 rc = ERROR_NOT_ENOUGH_MEMORY;
356 goto cleanup;
357 }
358 wcscpy(DeviceName, L"\\Device\\");
359 wcscat(DeviceName, UuidString);
360
361 /* Create export name */
362 ExportName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\Tcpip_") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
363 if (!ExportName)
364 {
365 DPRINT("HeapAlloc() failed\n");
366 rc = ERROR_NOT_ENOUGH_MEMORY;
367 goto cleanup;
368 }
369 wcscpy(ExportName, L"\\Device\\Tcpip_");
370 wcscat(ExportName, UuidString);
371
372 /* Write Tcpip parameters in new service Key */
373 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services", 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hKey, NULL);
374 if (rc != ERROR_SUCCESS)
375 {
376 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
377 goto cleanup;
378 }
379 rc = RegCreateKeyExW(hKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hNetworkKey, NULL);
380 if (rc != ERROR_SUCCESS)
381 {
382 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
383 goto cleanup;
384 }
385 RegCloseKey(hKey);
386 hKey = NULL;
387 rc = RegCreateKeyExW(hNetworkKey, L"Parameters\\Tcpip", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL);
388 if (rc != ERROR_SUCCESS)
389 {
390 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
391 goto cleanup;
392 }
393 RegCloseKey(hNetworkKey);
394 hNetworkKey = NULL;
395 rc = RegSetValueExW(hKey, L"DefaultGateway", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
396 if (rc != ERROR_SUCCESS)
397 {
398 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
399 goto cleanup;
400 }
401 rc = RegSetValueExW(hKey, L"IPAddress", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
402 if (rc != ERROR_SUCCESS)
403 {
404 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
405 goto cleanup;
406 }
407 rc = RegSetValueExW(hKey, L"SubnetMask", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
408 if (rc != ERROR_SUCCESS)
409 {
410 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
411 goto cleanup;
412 }
413 RegCloseKey(hKey);
414 hKey = NULL;
415
416 /* Write 'Linkage' key in hardware key */
417 #if _WIN32_WINNT >= 0x502
418 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
419 #else
420 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
421 #endif
422 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
423 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
424 if (hKey == INVALID_HANDLE_VALUE)
425 {
426 hKey = NULL;
427 rc = GetLastError();
428 DPRINT("SetupDiCreateDevRegKeyW() failed with error 0x%lx\n", rc);
429 goto cleanup;
430 }
431 rc = RegSetValueExW(hKey, L"NetCfgInstanceId", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
432 if (rc != ERROR_SUCCESS)
433 {
434 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
435 goto cleanup;
436 }
437 rc = RegSetValueExW(hKey, L"Characteristics", 0, REG_DWORD, (const BYTE*)&Characteristics, sizeof(DWORD));
438 if (rc != ERROR_SUCCESS)
439 {
440 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
441 goto cleanup;
442 }
443 if (BusType)
444 rc = RegSetValueExW(hKey, L"BusType", 0, REG_SZ, (const BYTE*)BusType, (wcslen(BusType) + 1) * sizeof(WCHAR));
445 if (rc != ERROR_SUCCESS)
446 {
447 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
448 goto cleanup;
449 }
450 rc = RegCreateKeyExW(hKey, L"Linkage", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hLinkageKey, NULL);
451 if (rc != ERROR_SUCCESS)
452 {
453 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
454 goto cleanup;
455 }
456 rc = RegSetValueExW(hLinkageKey, L"Export", 0, REG_SZ, (const BYTE*)DeviceName, (wcslen(DeviceName) + 1) * sizeof(WCHAR));
457 if (rc != ERROR_SUCCESS)
458 {
459 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
460 goto cleanup;
461 }
462 rc = RegSetValueExW(hLinkageKey, L"RootDevice", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
463 if (rc != ERROR_SUCCESS)
464 {
465 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
466 goto cleanup;
467 }
468 rc = RegSetValueExW(hLinkageKey, L"UpperBind", 0, REG_SZ, (const BYTE*)L"Tcpip", (wcslen(L"Tcpip") + 1) * sizeof(WCHAR));
469 if (rc != ERROR_SUCCESS)
470 {
471 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
472 goto cleanup;
473 }
474 RegCloseKey(hKey);
475 hKey = NULL;
476
477 /* Write connection information in network subkey */
478 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);
479 if (rc != ERROR_SUCCESS)
480 {
481 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
482 goto cleanup;
483 }
484 rc = RegCreateKeyExW(hNetworkKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hKey, NULL);
485 if (rc != ERROR_SUCCESS)
486 {
487 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
488 goto cleanup;
489 }
490 rc = RegCreateKeyExW(hKey, L"Connection", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hConnectionKey, NULL);
491 RegCloseKey(hKey);
492 hKey = NULL;
493 if (rc != ERROR_SUCCESS)
494 {
495 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
496 goto cleanup;
497 }
498 rc = RegSetValueExW(hConnectionKey, L"Name", 0, REG_SZ, (const BYTE*)L"Network connection", (wcslen(L"Network connection") + 1) * sizeof(WCHAR));
499 if (rc != ERROR_SUCCESS)
500 {
501 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
502 goto cleanup;
503 }
504 rc = RegSetValueExW(hConnectionKey, L"PnpInstanceId", 0, REG_SZ, (const BYTE*)InstanceId, (wcslen(InstanceId) + 1) * sizeof(WCHAR));
505 if (rc != ERROR_SUCCESS)
506 {
507 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
508 goto cleanup;
509 }
510 dwShowIcon = 1;
511 rc = RegSetValueExW(hConnectionKey, L"ShowIcon", 0, REG_DWORD, (const BYTE*)&dwShowIcon, sizeof(dwShowIcon));
512 if (rc != ERROR_SUCCESS)
513 {
514 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
515 goto cleanup;
516 }
517
518 /* Write linkage information in Tcpip service */
519 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);
520 if (rc != ERROR_SUCCESS)
521 {
522 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
523 goto cleanup;
524 }
525 rc = AppendStringToMultiSZ(hKey, L"Bind", DeviceName);
526 if (rc != ERROR_SUCCESS)
527 {
528 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
529 goto cleanup;
530 }
531 rc = AppendStringToMultiSZ(hKey, L"Export", ExportName);
532 if (rc != ERROR_SUCCESS)
533 {
534 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
535 goto cleanup;
536 }
537 rc = AppendStringToMultiSZ(hKey, L"Route", UuidString);
538 if (rc != ERROR_SUCCESS)
539 {
540 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
541 goto cleanup;
542 }
543
544 /* Install additionnal services */
545 rc = InstallAdditionalServices(NULL);
546 if (rc != ERROR_SUCCESS)
547 {
548 DPRINT("InstallAdditionalServices() failed with error 0x%lx\n", rc);
549 goto cleanup;
550 }
551
552 rc = ERROR_SUCCESS;
553
554 cleanup:
555 HeapFree(GetProcessHeap(), 0, InstanceId);
556 HeapFree(GetProcessHeap(), 0, DeviceName);
557 HeapFree(GetProcessHeap(), 0, ExportName);
558 if (hKey != NULL)
559 RegCloseKey(hKey);
560 if (hNetworkKey != NULL)
561 RegCloseKey(hNetworkKey);
562 if (hLinkageKey != NULL)
563 RegCloseKey(hLinkageKey);
564 if (hConnectionKey != NULL)
565 RegCloseKey(hConnectionKey);
566 return rc;
567 }
568
569 static DWORD
570 InstallNetClient(VOID)
571 {
572 DPRINT1("Installation of network clients is not yet supported\n");
573 return ERROR_GEN_FAILURE;
574 }
575
576 static DWORD
577 InstallNetService(VOID)
578 {
579 DPRINT1("Installation of network services is not yet supported\n");
580 return ERROR_GEN_FAILURE;
581 }
582
583 static DWORD
584 InstallNetTransport(VOID)
585 {
586 DPRINT1("Installation of network protocols is not yet supported\n");
587 return ERROR_GEN_FAILURE;
588 }
589
590 DWORD WINAPI
591 NetClassInstaller(
592 IN DI_FUNCTION InstallFunction,
593 IN HDEVINFO DeviceInfoSet,
594 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
595 {
596 SP_DRVINFO_DATA_W DriverInfoData;
597 SP_DRVINFO_DETAIL_DATA_W DriverInfoDetail;
598 WCHAR SectionName[LINE_LEN];
599 HINF hInf = INVALID_HANDLE_VALUE;
600 INFCONTEXT InfContext;
601 UINT ErrorLine;
602 INT CharacteristicsInt;
603 DWORD Characteristics;
604 LPWSTR BusType = NULL;
605 RPC_STATUS RpcStatus;
606 UUID Uuid;
607 LPWSTR UuidRpcString = NULL;
608 LPWSTR UuidString = NULL;
609 LONG rc;
610 DWORD dwLength;
611
612 if (InstallFunction != DIF_INSTALLDEVICE)
613 return ERROR_DI_DO_DEFAULT;
614
615 DPRINT("%lu %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
616
617 /* Get driver info details */
618 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
619 if (!SetupDiGetSelectedDriverW(DeviceInfoSet, DeviceInfoData, &DriverInfoData))
620 {
621 rc = GetLastError();
622 DPRINT("SetupDiGetSelectedDriverW() failed with error 0x%lx\n", rc);
623 goto cleanup;
624 }
625 DriverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
626 if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet, DeviceInfoData, &DriverInfoData, &DriverInfoDetail, sizeof(DriverInfoDetail), NULL)
627 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
628 {
629 rc = GetLastError();
630 DPRINT("SetupDiGetDriverInfoDetailW() failed with error 0x%lx\n", rc);
631 goto cleanup;
632 }
633 hInf = SetupOpenInfFileW(DriverInfoDetail.InfFileName, NULL, INF_STYLE_WIN4, &ErrorLine);
634 if (hInf == INVALID_HANDLE_VALUE)
635 {
636 rc = GetLastError();
637 DPRINT("SetupOpenInfFileW() failed with error 0x%lx\n", rc);
638 goto cleanup;
639 }
640 if (!SetupDiGetActualSectionToInstallW(hInf, DriverInfoDetail.SectionName, SectionName, LINE_LEN, NULL, NULL))
641 {
642 rc = GetLastError();
643 DPRINT("SetupDiGetActualSectionToInstallW() failed with error 0x%lx\n", rc);
644 goto cleanup;
645 }
646
647 /* Get Characteristics and BusType (optional) from .inf file */
648 if (!SetupFindFirstLineW(hInf, SectionName, L"Characteristics", &InfContext))
649 {
650 rc = GetLastError();
651 DPRINT("Unable to find key %S in section %S of file %S (error 0x%lx)\n",
652 L"Characteristics", SectionName, DriverInfoDetail.InfFileName, rc);
653 goto cleanup;
654 }
655 if (!SetupGetIntField(&InfContext, 1, &CharacteristicsInt))
656 {
657 rc = GetLastError();
658 DPRINT("SetupGetIntField() failed with error 0x%lx\n", rc);
659 goto cleanup;
660 }
661 Characteristics = (DWORD)CharacteristicsInt;
662 if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
663 {
664 if (SetupFindFirstLineW(hInf, SectionName, L"BusType", &InfContext))
665 {
666 if (!SetupGetStringFieldW(&InfContext, 1, NULL, 0, &dwLength))
667 {
668 rc = GetLastError();
669 DPRINT("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
670 goto cleanup;
671 }
672 BusType = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
673 if (!BusType)
674 {
675 DPRINT("HeapAlloc() failed\n");
676 rc = ERROR_NOT_ENOUGH_MEMORY;
677 goto cleanup;
678 }
679 if (!SetupGetStringFieldW(&InfContext, 1, BusType, dwLength, NULL))
680 {
681 rc = GetLastError();
682 DPRINT("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
683 goto cleanup;
684 }
685 }
686 }
687
688 /* Create a new UUID */
689 RpcStatus = UuidCreate(&Uuid);
690 if (RpcStatus != RPC_S_OK && RpcStatus != RPC_S_UUID_LOCAL_ONLY)
691 {
692 DPRINT("UuidCreate() failed with RPC status 0x%lx\n", RpcStatus);
693 rc = ERROR_GEN_FAILURE;
694 goto cleanup;
695 }
696 RpcStatus = UuidToStringW(&Uuid, &UuidRpcString);
697 if (RpcStatus != RPC_S_OK)
698 {
699 DPRINT("UuidToStringW() failed with RPC status 0x%lx\n", RpcStatus);
700 rc = ERROR_GEN_FAILURE;
701 goto cleanup;
702 }
703
704 /* Add curly braces around Uuid */
705 UuidString = HeapAlloc(GetProcessHeap(), 0, (2 + wcslen(UuidRpcString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
706 if (!UuidString)
707 {
708 DPRINT("HeapAlloc() failed\n");
709 rc = ERROR_NOT_ENOUGH_MEMORY;
710 goto cleanup;
711 }
712 wcscpy(UuidString, L"{");
713 wcscat(UuidString, UuidRpcString);
714 wcscat(UuidString, L"}");
715
716 if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
717 rc = InstallNetDevice(DeviceInfoSet, DeviceInfoData, UuidString, Characteristics, BusType);
718 else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETCLIENT))
719 rc = InstallNetClient();
720 else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETSERVICE))
721 rc = InstallNetService();
722 else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETTRANS))
723 rc = InstallNetTransport();
724 else
725 {
726 DPRINT("Invalid class guid\n");
727 rc = ERROR_GEN_FAILURE;
728 }
729
730 cleanup:
731 if (hInf != INVALID_HANDLE_VALUE)
732 SetupCloseInfFile(hInf);
733 if (UuidRpcString != NULL)
734 RpcStringFreeW(&UuidRpcString);
735 HeapFree(GetProcessHeap(), 0, BusType);
736 HeapFree(GetProcessHeap(), 0, UuidString);
737
738 if (rc == ERROR_SUCCESS)
739 rc = ERROR_DI_DO_DEFAULT;
740 DPRINT("Returning 0x%lx\n", rc);
741 return rc;
742 }