Sync with trunk rev.61910 to get latest improvements and bugfixes.
[reactos.git] / 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 #include "precomp.h"
11
12 #include <olectl.h>
13
14 #define NTOS_MODE_USER
15 #include <ndk/iofuncs.h>
16 #include <ndk/rtlfuncs.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 HINSTANCE netcfgx_hInstance;
22 const GUID CLSID_TcpipConfigNotifyObject = {0xA907657F, 0x6FDF, 0x11D0, {0x8E, 0xFB, 0x00, 0xC0, 0x4F, 0xD9, 0x12, 0xB2}};
23
24 static INTERFACE_TABLE InterfaceTable[] =
25 {
26 {
27 &CLSID_CNetCfg,
28 INetCfg_Constructor
29 },
30 {
31 &CLSID_TcpipConfigNotifyObject,
32 TcpipConfigNotify_Constructor
33 },
34 {
35 NULL,
36 NULL
37 }
38 };
39
40 BOOL
41 WINAPI
42 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
43 {
44 switch (fdwReason)
45 {
46 case DLL_PROCESS_ATTACH:
47 netcfgx_hInstance = hinstDLL;
48 DisableThreadLibraryCalls(netcfgx_hInstance);
49 break;
50 default:
51 break;
52 }
53
54 return TRUE;
55 }
56
57 HRESULT
58 WINAPI
59 DllCanUnloadNow(void)
60 {
61 return S_FALSE;
62 }
63
64 STDAPI
65 DllRegisterServer(void)
66 {
67 HKEY hKey, hSubKey;
68 LPOLESTR pStr;
69 WCHAR szName[MAX_PATH] = L"CLSID\\";
70
71 if (FAILED(StringFromCLSID(&CLSID_CNetCfg, &pStr)))
72 return SELFREG_E_CLASS;
73
74 wcscpy(&szName[6], pStr);
75 CoTaskMemFree(pStr);
76
77 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, szName, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
78 return SELFREG_E_CLASS;
79
80 if (RegCreateKeyExW(hKey, L"InProcServer32", 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
81 {
82 if (!GetModuleFileNameW(netcfgx_hInstance, szName, sizeof(szName)/sizeof(WCHAR)))
83 {
84 RegCloseKey(hSubKey);
85 RegCloseKey(hKey);
86 return SELFREG_E_CLASS;
87 }
88 szName[(sizeof(szName)/sizeof(WCHAR))-1] = L'\0';
89 RegSetValueW(hSubKey, NULL, REG_SZ, szName, (wcslen(szName)+1) * sizeof(WCHAR));
90 RegSetValueExW(hSubKey, L"ThreadingModel", 0, REG_SZ, (LPBYTE)L"Both", 10);
91 RegCloseKey(hSubKey);
92 }
93
94 RegCloseKey(hKey);
95 return S_OK;
96 }
97
98 STDAPI
99 DllUnregisterServer(void)
100 {
101 //FIXME
102 // implement unregistering services
103 //
104 return S_OK;
105 }
106
107 STDAPI
108 DllGetClassObject(
109 REFCLSID rclsid,
110 REFIID riid,
111 LPVOID* ppv)
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
148 LONG
149 AppendStringToMultiSZ(
150 IN HKEY hKey,
151 IN PCWSTR ValueName,
152 IN PCWSTR ValueToAppend)
153 {
154 PWSTR Buffer = NULL;
155 DWORD dwRegType;
156 DWORD dwRequired, dwLength;
157 DWORD dwTmp;
158 LONG rc;
159
160 rc = RegQueryValueExW(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
184 rc = RegQueryValueExW(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(hKey,
211 ValueName,
212 0,
213 REG_MULTI_SZ,
214 (const BYTE*)Buffer,
215 dwLength);
216
217 cleanup:
218 HeapFree(GetProcessHeap(), 0, Buffer);
219 return rc;
220 }
221
222 /* Install a section of a .inf file
223 * Returns TRUE if success, FALSE if failure. Error code can
224 * be retrieved with GetLastError()
225 */
226 static
227 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
289 DWORD
290 InstallAdditionalServices(
291 IN HWND hWnd)
292 {
293 BOOL ret;
294 UNICODE_STRING TcpipServicePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip");
295
296 /* Install TCP/IP protocol */
297 ret = InstallInfSection(hWnd,
298 L"nettcpip.inf",
299 L"MS_TCPIP.PrimaryInstall",
300 L"MS_TCPIP.PrimaryInstall.Services");
301 if (!ret && GetLastError() != ERROR_FILE_NOT_FOUND)
302 {
303 DPRINT("InstallInfSection() failed with error 0x%lx\n", GetLastError());
304 return GetLastError();
305 }
306 else if (ret)
307 {
308 /* Start the TCP/IP driver */
309 ret = NtLoadDriver(&TcpipServicePath);
310 if (ret)
311 {
312 /* This isn't really fatal but we want to warn anyway */
313 DPRINT1("NtLoadDriver(TCPIP) failed with NTSTATUS 0x%lx\n", (NTSTATUS)ret);
314 }
315 }
316
317
318 /* You can add here more clients (SMB...) and services (DHCP server...) */
319
320 return ERROR_SUCCESS;
321 }
322
323 static
324 DWORD
325 InstallNetDevice(
326 IN HDEVINFO DeviceInfoSet,
327 IN PSP_DEVINFO_DATA DeviceInfoData,
328 LPCWSTR UuidString,
329 DWORD Characteristics,
330 LPCWSTR BusType)
331 {
332 LPWSTR InstanceId = NULL;
333 LPWSTR DeviceName = NULL;
334 LPWSTR ExportName = NULL;
335 LONG rc;
336 HKEY hKey = NULL;
337 HKEY hNetworkKey = NULL;
338 HKEY hLinkageKey = NULL;
339 HKEY hConnectionKey = NULL;
340 DWORD dwShowIcon, dwLength, dwValue;
341 WCHAR szBuffer[300];
342
343 /* Get Instance ID */
344 if (SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, NULL, 0, &dwLength))
345 {
346 DPRINT("SetupDiGetDeviceInstanceIdW() returned TRUE. FALSE expected\n");
347 rc = ERROR_GEN_FAILURE;
348 goto cleanup;
349 }
350
351 InstanceId = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
352 if (!InstanceId)
353 {
354 DPRINT("HeapAlloc() failed\n");
355 rc = ERROR_NOT_ENOUGH_MEMORY;
356 goto cleanup;
357 }
358
359 if (!SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, InstanceId, dwLength, NULL))
360 {
361 rc = GetLastError();
362 DPRINT("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", rc);
363 goto cleanup;
364 }
365
366 /* Create device name */
367 DeviceName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
368 if (!DeviceName)
369 {
370 DPRINT("HeapAlloc() failed\n");
371 rc = ERROR_NOT_ENOUGH_MEMORY;
372 goto cleanup;
373 }
374 wcscpy(DeviceName, L"\\Device\\");
375 wcscat(DeviceName, UuidString);
376
377 /* Create export name */
378 ExportName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\Tcpip_") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
379 if (!ExportName)
380 {
381 DPRINT("HeapAlloc() failed\n");
382 rc = ERROR_NOT_ENOUGH_MEMORY;
383 goto cleanup;
384 }
385 wcscpy(ExportName, L"\\Device\\Tcpip_");
386 wcscat(ExportName, UuidString);
387
388 /* Write Tcpip parameters in new service Key */
389 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services", 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hKey, NULL);
390 if (rc != ERROR_SUCCESS)
391 {
392 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
393 goto cleanup;
394 }
395
396 rc = RegCreateKeyExW(hKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, 0, NULL, &hNetworkKey, NULL);
397 if (rc != ERROR_SUCCESS)
398 {
399 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
400 goto cleanup;
401 }
402 RegCloseKey(hKey);
403 hKey = NULL;
404
405 rc = RegCreateKeyExW(hNetworkKey, L"Parameters\\Tcpip", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL);
406 if (rc != ERROR_SUCCESS)
407 {
408 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
409 goto cleanup;
410 }
411 RegCloseKey(hNetworkKey);
412 hNetworkKey = NULL;
413
414 rc = RegSetValueExW(hKey, L"DefaultGateway", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
415 if (rc != ERROR_SUCCESS)
416 {
417 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
418 goto cleanup;
419 }
420
421 rc = RegSetValueExW(hKey, L"IPAddress", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
422 if (rc != ERROR_SUCCESS)
423 {
424 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
425 goto cleanup;
426 }
427
428 rc = RegSetValueExW(hKey, L"SubnetMask", 0, REG_SZ, (const BYTE*)L"0.0.0.0", (wcslen(L"0.0.0.0") + 1) * sizeof(WCHAR));
429 if (rc != ERROR_SUCCESS)
430 {
431 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
432 goto cleanup;
433 }
434
435 dwValue = 1;
436 rc = RegSetValueExW(hKey, L"EnableDHCP", 0, REG_DWORD, (const BYTE*)&dwValue, sizeof(DWORD));
437 if (rc != ERROR_SUCCESS)
438 {
439 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
440 goto cleanup;
441 }
442 RegCloseKey(hKey);
443 hKey = NULL;
444
445 /* Write 'Linkage' key in hardware key */
446 #if _WIN32_WINNT >= 0x502
447 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
448 #else
449 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
450 #endif
451 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
452 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
453 if (hKey == INVALID_HANDLE_VALUE)
454 {
455 hKey = NULL;
456 rc = GetLastError();
457 DPRINT("SetupDiCreateDevRegKeyW() failed with error 0x%lx\n", rc);
458 goto cleanup;
459 }
460
461 rc = RegSetValueExW(hKey, L"NetCfgInstanceId", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
462 if (rc != ERROR_SUCCESS)
463 {
464 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
465 goto cleanup;
466 }
467
468 rc = RegSetValueExW(hKey, L"Characteristics", 0, REG_DWORD, (const BYTE*)&Characteristics, sizeof(DWORD));
469 if (rc != ERROR_SUCCESS)
470 {
471 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
472 goto cleanup;
473 }
474
475 if (BusType)
476 {
477 rc = RegSetValueExW(hKey, L"BusType", 0, REG_SZ, (const BYTE*)BusType, (wcslen(BusType) + 1) * sizeof(WCHAR));
478 if (rc != ERROR_SUCCESS)
479 {
480 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
481 goto cleanup;
482 }
483 }
484
485 rc = RegCreateKeyExW(hKey, L"Linkage", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hLinkageKey, NULL);
486 if (rc != ERROR_SUCCESS)
487 {
488 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
489 goto cleanup;
490 }
491
492 rc = RegSetValueExW(hLinkageKey, L"Export", 0, REG_SZ, (const BYTE*)DeviceName, (wcslen(DeviceName) + 1) * sizeof(WCHAR));
493 if (rc != ERROR_SUCCESS)
494 {
495 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
496 goto cleanup;
497 }
498
499 rc = RegSetValueExW(hLinkageKey, L"RootDevice", 0, REG_SZ, (const BYTE*)UuidString, (wcslen(UuidString) + 1) * sizeof(WCHAR));
500 if (rc != ERROR_SUCCESS)
501 {
502 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
503 goto cleanup;
504 }
505
506 rc = RegSetValueExW(hLinkageKey, L"UpperBind", 0, REG_SZ, (const BYTE*)L"Tcpip", (wcslen(L"Tcpip") + 1) * sizeof(WCHAR));
507 if (rc != ERROR_SUCCESS)
508 {
509 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
510 goto cleanup;
511 }
512 RegCloseKey(hKey);
513 hKey = NULL;
514
515 /* Write connection information in network subkey */
516 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);
517 if (rc != ERROR_SUCCESS)
518 {
519 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
520 goto cleanup;
521 }
522
523 rc = RegCreateKeyExW(hNetworkKey, UuidString, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hKey, NULL);
524 if (rc != ERROR_SUCCESS)
525 {
526 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
527 goto cleanup;
528 }
529
530 rc = RegCreateKeyExW(hKey, L"Connection", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hConnectionKey, NULL);
531 RegCloseKey(hKey);
532 hKey = NULL;
533 if (rc != ERROR_SUCCESS)
534 {
535 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
536 goto cleanup;
537 }
538
539 if (!LoadStringW(netcfgx_hInstance, IDS_NET_CONNECT, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
540 {
541 wcscpy(szBuffer,L"Network connection");
542 }
543
544 rc = RegSetValueExW(hConnectionKey, L"Name", 0, REG_SZ, (const BYTE*)szBuffer, (wcslen(szBuffer) + 1) * sizeof(WCHAR));
545 if (rc != ERROR_SUCCESS)
546 {
547 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
548 goto cleanup;
549 }
550
551 rc = RegSetValueExW(hConnectionKey, L"PnpInstanceId", 0, REG_SZ, (const BYTE*)InstanceId, (wcslen(InstanceId) + 1) * sizeof(WCHAR));
552 if (rc != ERROR_SUCCESS)
553 {
554 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
555 goto cleanup;
556 }
557
558 dwShowIcon = 1;
559 rc = RegSetValueExW(hConnectionKey, L"ShowIcon", 0, REG_DWORD, (const BYTE*)&dwShowIcon, sizeof(dwShowIcon));
560 if (rc != ERROR_SUCCESS)
561 {
562 DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
563 goto cleanup;
564 }
565
566 /* Write linkage information in Tcpip service */
567 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);
568 if (rc != ERROR_SUCCESS)
569 {
570 DPRINT("RegCreateKeyExW() failed with error 0x%lx\n", rc);
571 goto cleanup;
572 }
573 rc = AppendStringToMultiSZ(hKey, L"Bind", DeviceName);
574 if (rc != ERROR_SUCCESS)
575 {
576 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
577 goto cleanup;
578 }
579 rc = AppendStringToMultiSZ(hKey, L"Export", ExportName);
580 if (rc != ERROR_SUCCESS)
581 {
582 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
583 goto cleanup;
584 }
585 rc = AppendStringToMultiSZ(hKey, L"Route", UuidString);
586 if (rc != ERROR_SUCCESS)
587 {
588 DPRINT("AppendStringToMultiSZ() failed with error 0x%lx\n", rc);
589 goto cleanup;
590 }
591
592 /* Install additionnal services */
593 rc = InstallAdditionalServices(NULL);
594 if (rc != ERROR_SUCCESS)
595 {
596 DPRINT("InstallAdditionalServices() failed with error 0x%lx\n", rc);
597 goto cleanup;
598 }
599
600 rc = ERROR_SUCCESS;
601
602 cleanup:
603 HeapFree(GetProcessHeap(), 0, InstanceId);
604 HeapFree(GetProcessHeap(), 0, DeviceName);
605 HeapFree(GetProcessHeap(), 0, ExportName);
606 if (hKey != NULL)
607 RegCloseKey(hKey);
608 if (hNetworkKey != NULL)
609 RegCloseKey(hNetworkKey);
610 if (hLinkageKey != NULL)
611 RegCloseKey(hLinkageKey);
612 if (hConnectionKey != NULL)
613 RegCloseKey(hConnectionKey);
614 return rc;
615 }
616
617 static
618 DWORD
619 InstallNetClient(VOID)
620 {
621 DPRINT1("Installation of network clients is not yet supported\n");
622 return ERROR_GEN_FAILURE;
623 }
624
625 static
626 DWORD
627 InstallNetService(VOID)
628 {
629 DPRINT1("Installation of network services is not yet supported\n");
630 return ERROR_GEN_FAILURE;
631 }
632
633 static
634 DWORD
635 InstallNetTransport(VOID)
636 {
637 DPRINT1("Installation of network protocols is not yet supported\n");
638 return ERROR_GEN_FAILURE;
639 }
640
641 DWORD
642 WINAPI
643 NetClassInstaller(
644 IN DI_FUNCTION InstallFunction,
645 IN HDEVINFO DeviceInfoSet,
646 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
647 {
648 SP_DRVINFO_DATA_W DriverInfoData;
649 SP_DRVINFO_DETAIL_DATA_W DriverInfoDetail;
650 WCHAR SectionName[LINE_LEN];
651 HINF hInf = INVALID_HANDLE_VALUE;
652 INFCONTEXT InfContext;
653 UINT ErrorLine;
654 INT CharacteristicsInt;
655 DWORD Characteristics;
656 LPWSTR BusType = NULL;
657 RPC_STATUS RpcStatus;
658 UUID Uuid;
659 LPWSTR UuidRpcString = NULL;
660 LPWSTR UuidString = NULL;
661 LONG rc;
662 DWORD dwLength;
663
664 if (InstallFunction != DIF_INSTALLDEVICE)
665 return ERROR_DI_DO_DEFAULT;
666
667 DPRINT("%lu %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
668
669 /* Get driver info details */
670 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
671 if (!SetupDiGetSelectedDriverW(DeviceInfoSet, DeviceInfoData, &DriverInfoData))
672 {
673 rc = GetLastError();
674 DPRINT("SetupDiGetSelectedDriverW() failed with error 0x%lx\n", rc);
675 goto cleanup;
676 }
677
678 DriverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
679 if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet, DeviceInfoData, &DriverInfoData, &DriverInfoDetail, sizeof(DriverInfoDetail), NULL)
680 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
681 {
682 rc = GetLastError();
683 DPRINT("SetupDiGetDriverInfoDetailW() failed with error 0x%lx\n", rc);
684 goto cleanup;
685 }
686
687 hInf = SetupOpenInfFileW(DriverInfoDetail.InfFileName, NULL, INF_STYLE_WIN4, &ErrorLine);
688 if (hInf == INVALID_HANDLE_VALUE)
689 {
690 rc = GetLastError();
691 DPRINT("SetupOpenInfFileW() failed with error 0x%lx\n", rc);
692 goto cleanup;
693 }
694
695 if (!SetupDiGetActualSectionToInstallW(hInf, DriverInfoDetail.SectionName, SectionName, LINE_LEN, NULL, NULL))
696 {
697 rc = GetLastError();
698 DPRINT("SetupDiGetActualSectionToInstallW() failed with error 0x%lx\n", rc);
699 goto cleanup;
700 }
701
702 /* Get Characteristics and BusType (optional) from .inf file */
703 if (!SetupFindFirstLineW(hInf, SectionName, L"Characteristics", &InfContext))
704 {
705 rc = GetLastError();
706 DPRINT("Unable to find key %S in section %S of file %S (error 0x%lx)\n",
707 L"Characteristics", SectionName, DriverInfoDetail.InfFileName, rc);
708 goto cleanup;
709 }
710
711 if (!SetupGetIntField(&InfContext, 1, &CharacteristicsInt))
712 {
713 rc = GetLastError();
714 DPRINT("SetupGetIntField() failed with error 0x%lx\n", rc);
715 goto cleanup;
716 }
717
718 Characteristics = (DWORD)CharacteristicsInt;
719 if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
720 {
721 if (SetupFindFirstLineW(hInf, SectionName, L"BusType", &InfContext))
722 {
723 if (!SetupGetStringFieldW(&InfContext, 1, NULL, 0, &dwLength))
724 {
725 rc = GetLastError();
726 DPRINT("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
727 goto cleanup;
728 }
729
730 BusType = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
731 if (!BusType)
732 {
733 DPRINT("HeapAlloc() failed\n");
734 rc = ERROR_NOT_ENOUGH_MEMORY;
735 goto cleanup;
736 }
737
738 if (!SetupGetStringFieldW(&InfContext, 1, BusType, dwLength, NULL))
739 {
740 rc = GetLastError();
741 DPRINT("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
742 goto cleanup;
743 }
744 }
745 }
746
747 /* Create a new UUID */
748 RpcStatus = UuidCreate(&Uuid);
749 if (RpcStatus != RPC_S_OK && RpcStatus != RPC_S_UUID_LOCAL_ONLY)
750 {
751 DPRINT("UuidCreate() failed with RPC status 0x%lx\n", RpcStatus);
752 rc = ERROR_GEN_FAILURE;
753 goto cleanup;
754 }
755
756 RpcStatus = UuidToStringW(&Uuid, &UuidRpcString);
757 if (RpcStatus != RPC_S_OK)
758 {
759 DPRINT("UuidToStringW() failed with RPC status 0x%lx\n", RpcStatus);
760 rc = ERROR_GEN_FAILURE;
761 goto cleanup;
762 }
763
764 /* Add curly braces around Uuid */
765 UuidString = HeapAlloc(GetProcessHeap(), 0, (2 + wcslen(UuidRpcString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
766 if (!UuidString)
767 {
768 DPRINT("HeapAlloc() failed\n");
769 rc = ERROR_NOT_ENOUGH_MEMORY;
770 goto cleanup;
771 }
772
773 wcscpy(UuidString, L"{");
774 wcscat(UuidString, UuidRpcString);
775 wcscat(UuidString, L"}");
776
777 if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
778 rc = InstallNetDevice(DeviceInfoSet, DeviceInfoData, UuidString, Characteristics, BusType);
779 else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETCLIENT))
780 rc = InstallNetClient();
781 else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETSERVICE))
782 rc = InstallNetService();
783 else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETTRANS))
784 rc = InstallNetTransport();
785 else
786 {
787 DPRINT("Invalid class guid\n");
788 rc = ERROR_GEN_FAILURE;
789 }
790
791 cleanup:
792 if (hInf != INVALID_HANDLE_VALUE)
793 SetupCloseInfFile(hInf);
794 if (UuidRpcString != NULL)
795 RpcStringFreeW(&UuidRpcString);
796 HeapFree(GetProcessHeap(), 0, BusType);
797 HeapFree(GetProcessHeap(), 0, UuidString);
798
799 if (rc == ERROR_SUCCESS)
800 rc = ERROR_DI_DO_DEFAULT;
801 DPRINT("Returning 0x%lx\n", rc);
802 return rc;
803 }