[NEWDEV]
[reactos.git] / reactos / dll / win32 / newdev / newdev.c
1 /*
2 * New device installer (newdev.dll)
3 *
4 * Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
5 * 2005 Christoph von Wittich (Christoph@ActiveVB.de)
6 * 2009 Colin Finck (colin@reactos.org)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "newdev_private.h"
24
25 /* Global variables */
26 HINSTANCE hDllInstance;
27
28 static BOOL
29 SearchDriver(
30 IN PDEVINSTDATA DevInstData,
31 IN LPCWSTR Directory OPTIONAL,
32 IN LPCWSTR InfFile OPTIONAL);
33
34 /*
35 * @implemented
36 */
37 BOOL WINAPI
38 UpdateDriverForPlugAndPlayDevicesW(
39 IN HWND hwndParent,
40 IN LPCWSTR HardwareId,
41 IN LPCWSTR FullInfPath,
42 IN DWORD InstallFlags,
43 OUT PBOOL bRebootRequired OPTIONAL)
44 {
45 DEVINSTDATA DevInstData;
46 DWORD i;
47 LPWSTR Buffer = NULL;
48 DWORD BufferSize;
49 LPCWSTR CurrentHardwareId; /* Pointer into Buffer */
50 BOOL FoundHardwareId, FoundAtLeastOneDevice = FALSE;
51 BOOL ret = FALSE;
52
53 DevInstData.hDevInfo = INVALID_HANDLE_VALUE;
54
55 TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %s %s 0x%x %p)\n",
56 hwndParent, debugstr_w(HardwareId), debugstr_w(FullInfPath), InstallFlags, bRebootRequired);
57
58 /* FIXME: InstallFlags bRebootRequired ignored! */
59
60 /* Check flags */
61 if (InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE))
62 {
63 TRACE("Unknown flags: 0x%08lx\n", InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE));
64 SetLastError(ERROR_INVALID_FLAGS);
65 goto cleanup;
66 }
67
68 /* Enumerate all devices of the system */
69 DevInstData.hDevInfo = SetupDiGetClassDevsW(NULL, NULL, hwndParent, DIGCF_ALLCLASSES | DIGCF_PRESENT);
70 if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE)
71 goto cleanup;
72 DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
73 for (i = 0; ; i++)
74 {
75 if (!SetupDiEnumDeviceInfo(DevInstData.hDevInfo, i, &DevInstData.devInfoData))
76 {
77 if (GetLastError() != ERROR_NO_MORE_ITEMS)
78 {
79 TRACE("SetupDiEnumDeviceInfo() failed with error 0x%x\n", GetLastError());
80 goto cleanup;
81 }
82 /* This error was expected */
83 break;
84 }
85
86 /* Get Hardware ID */
87 HeapFree(GetProcessHeap(), 0, Buffer);
88 Buffer = NULL;
89 BufferSize = 0;
90 while (!SetupDiGetDeviceRegistryPropertyW(
91 DevInstData.hDevInfo,
92 &DevInstData.devInfoData,
93 SPDRP_HARDWAREID,
94 NULL,
95 (PBYTE)Buffer,
96 BufferSize,
97 &BufferSize))
98 {
99 if (GetLastError() == ERROR_FILE_NOT_FOUND)
100 {
101 Buffer = NULL;
102 break;
103 }
104 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
105 {
106 TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%x\n", GetLastError());
107 goto cleanup;
108 }
109 /* This error was expected */
110 HeapFree(GetProcessHeap(), 0, Buffer);
111 Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
112 if (!Buffer)
113 {
114 TRACE("HeapAlloc() failed\n", GetLastError());
115 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
116 goto cleanup;
117 }
118 }
119 if (Buffer == NULL)
120 continue;
121
122 /* Check if we match the given hardware ID */
123 FoundHardwareId = FALSE;
124 for (CurrentHardwareId = Buffer; *CurrentHardwareId != UNICODE_NULL; CurrentHardwareId += wcslen(CurrentHardwareId) + 1)
125 {
126 if (wcscmp(CurrentHardwareId, HardwareId) == 0)
127 {
128 FoundHardwareId = TRUE;
129 break;
130 }
131 }
132 if (!FoundHardwareId)
133 continue;
134
135 /* We need to try to update the driver of this device */
136
137 /* Get Instance ID */
138 HeapFree(GetProcessHeap(), 0, Buffer);
139 Buffer = NULL;
140 if (SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, NULL, 0, &BufferSize))
141 {
142 /* Error, as the output buffer should be too small */
143 SetLastError(ERROR_GEN_FAILURE);
144 goto cleanup;
145 }
146 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
147 {
148 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError());
149 goto cleanup;
150 }
151 else if ((Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize * sizeof(WCHAR))) == NULL)
152 {
153 TRACE("HeapAlloc() failed\n", GetLastError());
154 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
155 goto cleanup;
156 }
157 else if (!SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, Buffer, BufferSize, NULL))
158 {
159 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError());
160 goto cleanup;
161 }
162 TRACE("Trying to update the driver of %s\n", debugstr_w(Buffer));
163
164 /* Search driver in the specified .inf file */
165 if (!SearchDriver(&DevInstData, NULL, FullInfPath))
166 {
167 TRACE("SearchDriver() failed with error 0x%x\n", GetLastError());
168 continue;
169 }
170
171 /* FIXME: HACK! We shouldn't check of ERROR_PRIVILEGE_NOT_HELD */
172 //if (!InstallCurrentDriver(&DevInstData))
173 if (!InstallCurrentDriver(&DevInstData) && GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
174 {
175 TRACE("InstallCurrentDriver() failed with error 0x%x\n", GetLastError());
176 continue;
177 }
178
179 FoundAtLeastOneDevice = TRUE;
180 }
181
182 if (FoundAtLeastOneDevice)
183 {
184 SetLastError(NO_ERROR);
185 ret = TRUE;
186 }
187 else
188 {
189 TRACE("No device found with HardwareID %s\n", debugstr_w(HardwareId));
190 SetLastError(ERROR_NO_SUCH_DEVINST);
191 }
192
193 cleanup:
194 if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE)
195 SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo);
196 HeapFree(GetProcessHeap(), 0, Buffer);
197 return ret;
198 }
199
200 /*
201 * @implemented
202 */
203 BOOL WINAPI
204 UpdateDriverForPlugAndPlayDevicesA(
205 IN HWND hwndParent,
206 IN LPCSTR HardwareId,
207 IN LPCSTR FullInfPath,
208 IN DWORD InstallFlags,
209 OUT PBOOL bRebootRequired OPTIONAL)
210 {
211 BOOL Result;
212 LPWSTR HardwareIdW = NULL;
213 LPWSTR FullInfPathW = NULL;
214
215 int len = MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, NULL, 0);
216 HardwareIdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
217 if (!HardwareIdW)
218 {
219 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
220 return FALSE;
221 }
222 MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, HardwareIdW, len);
223
224 len = MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, NULL, 0);
225 FullInfPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
226 if (!FullInfPathW)
227 {
228 HeapFree(GetProcessHeap(), 0, HardwareIdW);
229 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
230 return FALSE;
231 }
232 MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, FullInfPathW, len);
233
234 Result = UpdateDriverForPlugAndPlayDevicesW(
235 hwndParent,
236 HardwareIdW,
237 FullInfPathW,
238 InstallFlags,
239 bRebootRequired);
240
241 HeapFree(GetProcessHeap(), 0, HardwareIdW);
242 HeapFree(GetProcessHeap(), 0, FullInfPathW);
243
244 return Result;
245 }
246
247 /* Directory and InfFile MUST NOT be specified simultaneously */
248 static BOOL
249 SearchDriver(
250 IN PDEVINSTDATA DevInstData,
251 IN LPCWSTR Directory OPTIONAL,
252 IN LPCWSTR InfFile OPTIONAL)
253 {
254 SP_DEVINSTALL_PARAMS_W DevInstallParams = {0,};
255 BOOL ret;
256
257 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
258 if (!SetupDiGetDeviceInstallParamsW(DevInstData->hDevInfo, &DevInstData->devInfoData, &DevInstallParams))
259 {
260 TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%x\n", GetLastError());
261 return FALSE;
262 }
263 DevInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
264
265 if (InfFile)
266 {
267 DevInstallParams.Flags |= DI_ENUMSINGLEINF;
268 wcsncpy(DevInstallParams.DriverPath, InfFile, MAX_PATH);
269 }
270 else if (Directory)
271 {
272 DevInstallParams.Flags &= ~DI_ENUMSINGLEINF;
273 wcsncpy(DevInstallParams.DriverPath, Directory, MAX_PATH);
274 }
275 else
276 {
277 DevInstallParams.Flags &= ~DI_ENUMSINGLEINF;
278 *DevInstallParams.DriverPath = '\0';
279 }
280
281 ret = SetupDiSetDeviceInstallParamsW(
282 DevInstData->hDevInfo,
283 &DevInstData->devInfoData,
284 &DevInstallParams);
285 if (!ret)
286 {
287 TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%x\n", GetLastError());
288 return FALSE;
289 }
290
291 ret = SetupDiBuildDriverInfoList(
292 DevInstData->hDevInfo,
293 &DevInstData->devInfoData,
294 SPDIT_COMPATDRIVER);
295 if (!ret)
296 {
297 TRACE("SetupDiBuildDriverInfoList() failed with error 0x%x\n", GetLastError());
298 return FALSE;
299 }
300
301 DevInstData->drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
302 ret = SetupDiEnumDriverInfoW(
303 DevInstData->hDevInfo,
304 &DevInstData->devInfoData,
305 SPDIT_COMPATDRIVER,
306 0,
307 &DevInstData->drvInfoData);
308 if (!ret)
309 {
310 if (GetLastError() == ERROR_NO_MORE_ITEMS)
311 return FALSE;
312 TRACE("SetupDiEnumDriverInfo() failed with error 0x%x\n", GetLastError());
313 return FALSE;
314 }
315
316 return TRUE;
317 }
318
319 static BOOL
320 IsDots(IN LPCWSTR str)
321 {
322 if(wcscmp(str, L".") && wcscmp(str, L"..")) return FALSE;
323 return TRUE;
324 }
325
326 static LPCWSTR
327 GetFileExt(IN LPWSTR FileName)
328 {
329 LPCWSTR Dot;
330
331 Dot = wcsrchr(FileName, '.');
332 if (!Dot)
333 return L"";
334
335 return Dot;
336 }
337
338 static BOOL
339 SearchDriverRecursive(
340 IN PDEVINSTDATA DevInstData,
341 IN LPCWSTR Path)
342 {
343 WIN32_FIND_DATAW wfd;
344 WCHAR DirPath[MAX_PATH];
345 WCHAR FileName[MAX_PATH];
346 WCHAR FullPath[MAX_PATH];
347 WCHAR LastDirPath[MAX_PATH] = L"";
348 WCHAR PathWithPattern[MAX_PATH];
349 BOOL ok = TRUE;
350 BOOL retval = FALSE;
351 HANDLE hFindFile = INVALID_HANDLE_VALUE;
352
353 wcscpy(DirPath, Path);
354
355 if (DirPath[wcslen(DirPath) - 1] != '\\')
356 wcscat(DirPath, L"\\");
357
358 wcscpy(PathWithPattern, DirPath);
359 wcscat(PathWithPattern, L"\\*");
360
361 for (hFindFile = FindFirstFileW(PathWithPattern, &wfd);
362 ok && hFindFile != INVALID_HANDLE_VALUE;
363 ok = FindNextFileW(hFindFile, &wfd))
364 {
365
366 wcscpy(FileName, wfd.cFileName);
367 if (IsDots(FileName))
368 continue;
369
370 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
371 {
372 /* Recursive search */
373 wcscpy(FullPath, DirPath);
374 wcscat(FullPath, FileName);
375 if (SearchDriverRecursive(DevInstData, FullPath))
376 {
377 retval = TRUE;
378 /* We continue the search for a better driver */
379 }
380 }
381 else
382 {
383 LPCWSTR pszExtension = GetFileExt(FileName);
384
385 if ((_wcsicmp(pszExtension, L".inf") == 0) && (wcscmp(LastDirPath, DirPath) != 0))
386 {
387 wcscpy(LastDirPath, DirPath);
388
389 if (wcslen(DirPath) > MAX_PATH)
390 /* Path is too long to be searched */
391 continue;
392
393 if (SearchDriver(DevInstData, DirPath, NULL))
394 {
395 retval = TRUE;
396 /* We continue the search for a better driver */
397 }
398
399 }
400 }
401 }
402
403 if (hFindFile != INVALID_HANDLE_VALUE)
404 FindClose(hFindFile);
405 return retval;
406 }
407
408 BOOL
409 ScanFoldersForDriver(
410 IN PDEVINSTDATA DevInstData)
411 {
412 BOOL result;
413
414 /* Search in default location */
415 result = SearchDriver(DevInstData, NULL, NULL);
416
417 if (DevInstData->CustomSearchPath)
418 {
419 /* Search only in specified paths */
420 /* We need to check all specified directories to be
421 * sure to find the best driver for the device.
422 */
423 LPCWSTR Path;
424 for (Path = DevInstData->CustomSearchPath; *Path != '\0'; Path += wcslen(Path) + 1)
425 {
426 TRACE("Search driver in %s\n", debugstr_w(Path));
427 if (wcslen(Path) == 2 && Path[1] == ':')
428 {
429 if (SearchDriverRecursive(DevInstData, Path))
430 result = TRUE;
431 }
432 else
433 {
434 if (SearchDriver(DevInstData, Path, NULL))
435 result = TRUE;
436 }
437 }
438 }
439
440 return result;
441 }
442
443 BOOL
444 PrepareFoldersToScan(
445 IN PDEVINSTDATA DevInstData,
446 IN BOOL IncludeRemovableDevices,
447 IN BOOL IncludeCustomPath,
448 IN HWND hwndCombo OPTIONAL)
449 {
450 WCHAR drive[] = {'?',':',0};
451 DWORD dwDrives = 0;
452 DWORD i;
453 UINT nType;
454 DWORD CustomTextLength = 0;
455 DWORD LengthNeeded = 0;
456 LPWSTR Buffer;
457
458 /* Calculate length needed to store the search paths */
459 if (IncludeRemovableDevices)
460 {
461 dwDrives = GetLogicalDrives();
462 for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
463 {
464 if (dwDrives & i)
465 {
466 nType = GetDriveTypeW(drive);
467 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
468 {
469 LengthNeeded += 3;
470 }
471 }
472 }
473 }
474 if (IncludeCustomPath)
475 {
476 CustomTextLength = 1 + ComboBox_GetTextLength(hwndCombo);
477 LengthNeeded += CustomTextLength;
478 }
479
480 /* Allocate space for search paths */
481 HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath);
482 DevInstData->CustomSearchPath = Buffer = HeapAlloc(
483 GetProcessHeap(),
484 0,
485 (LengthNeeded + 1) * sizeof(WCHAR));
486 if (!Buffer)
487 {
488 TRACE("HeapAlloc() failed\n");
489 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
490 return FALSE;
491 }
492
493 /* Fill search paths */
494 if (IncludeRemovableDevices)
495 {
496 for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
497 {
498 if (dwDrives & i)
499 {
500 nType = GetDriveTypeW(drive);
501 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
502 {
503 Buffer += 1 + swprintf(Buffer, drive);
504 }
505 }
506 }
507 }
508 if (IncludeCustomPath)
509 {
510 Buffer += 1 + GetWindowTextW(hwndCombo, Buffer, CustomTextLength);
511 }
512 *Buffer = '\0';
513
514 return TRUE;
515 }
516
517 BOOL
518 InstallCurrentDriver(
519 IN PDEVINSTDATA DevInstData)
520 {
521 BOOL ret;
522
523 TRACE("Installing driver %s: %s\n",
524 debugstr_w(DevInstData->drvInfoData.MfgName),
525 debugstr_w(DevInstData->drvInfoData.Description));
526
527 ret = SetupDiCallClassInstaller(
528 DIF_SELECTBESTCOMPATDRV,
529 DevInstData->hDevInfo,
530 &DevInstData->devInfoData);
531 if (!ret)
532 {
533 TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%x\n", GetLastError());
534 return FALSE;
535 }
536
537 ret = SetupDiCallClassInstaller(
538 DIF_ALLOW_INSTALL,
539 DevInstData->hDevInfo,
540 &DevInstData->devInfoData);
541 if (!ret)
542 {
543 TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%x\n", GetLastError());
544 return FALSE;
545 }
546
547 ret = SetupDiCallClassInstaller(
548 DIF_NEWDEVICEWIZARD_PREANALYZE,
549 DevInstData->hDevInfo,
550 &DevInstData->devInfoData);
551 if (!ret)
552 {
553 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%x\n", GetLastError());
554 return FALSE;
555 }
556
557 ret = SetupDiCallClassInstaller(
558 DIF_NEWDEVICEWIZARD_POSTANALYZE,
559 DevInstData->hDevInfo,
560 &DevInstData->devInfoData);
561 if (!ret)
562 {
563 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%x\n", GetLastError());
564 return FALSE;
565 }
566
567 ret = SetupDiCallClassInstaller(
568 DIF_INSTALLDEVICEFILES,
569 DevInstData->hDevInfo,
570 &DevInstData->devInfoData);
571 if (!ret)
572 {
573 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%x\n", GetLastError());
574 return FALSE;
575 }
576
577 ret = SetupDiCallClassInstaller(
578 DIF_REGISTER_COINSTALLERS,
579 DevInstData->hDevInfo,
580 &DevInstData->devInfoData);
581 if (!ret)
582 {
583 TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%x\n", GetLastError());
584 return FALSE;
585 }
586
587 ret = SetupDiCallClassInstaller(
588 DIF_INSTALLINTERFACES,
589 DevInstData->hDevInfo,
590 &DevInstData->devInfoData);
591 if (!ret)
592 {
593 TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%x\n", GetLastError());
594 return FALSE;
595 }
596
597 ret = SetupDiCallClassInstaller(
598 DIF_INSTALLDEVICE,
599 DevInstData->hDevInfo,
600 &DevInstData->devInfoData);
601 if (!ret)
602 {
603 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%x\n", GetLastError());
604 return FALSE;
605 }
606
607 ret = SetupDiCallClassInstaller(
608 DIF_NEWDEVICEWIZARD_FINISHINSTALL,
609 DevInstData->hDevInfo,
610 &DevInstData->devInfoData);
611 if (!ret)
612 {
613 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%x\n", GetLastError());
614 return FALSE;
615 }
616
617 ret = SetupDiCallClassInstaller(
618 DIF_DESTROYPRIVATEDATA,
619 DevInstData->hDevInfo,
620 &DevInstData->devInfoData);
621 if (!ret)
622 {
623 TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%x\n", GetLastError());
624 return FALSE;
625 }
626
627 return TRUE;
628 }
629
630 /*
631 * @implemented
632 */
633 BOOL WINAPI
634 DevInstallW(
635 IN HWND hWndParent,
636 IN HINSTANCE hInstance,
637 IN LPCWSTR InstanceId,
638 IN INT Show)
639 {
640 PDEVINSTDATA DevInstData = NULL;
641 BOOL ret;
642 DWORD config_flags;
643 BOOL retval = FALSE;
644
645 TRACE("(%p, %p, %s, %d)\n", hWndParent, hInstance, debugstr_w(InstanceId), Show);
646
647 if (!IsUserAdmin())
648 {
649 /* XP kills the process... */
650 ExitProcess(ERROR_ACCESS_DENIED);
651 }
652
653 DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
654 if (!DevInstData)
655 {
656 TRACE("HeapAlloc() failed\n");
657 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
658 goto cleanup;
659 }
660
661 /* Clear devinst data */
662 ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
663 DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
664
665 /* Fill devinst data */
666 DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
667 if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
668 {
669 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError());
670 goto cleanup;
671 }
672
673 DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
674 ret = SetupDiOpenDeviceInfoW(
675 DevInstData->hDevInfo,
676 InstanceId,
677 NULL,
678 0, /* Open flags */
679 &DevInstData->devInfoData);
680 if (!ret)
681 {
682 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n",
683 GetLastError(), debugstr_w(InstanceId));
684 DevInstData->devInfoData.cbSize = 0;
685 goto cleanup;
686 }
687
688 SetLastError(ERROR_GEN_FAILURE);
689 ret = SetupDiGetDeviceRegistryProperty(
690 DevInstData->hDevInfo,
691 &DevInstData->devInfoData,
692 SPDRP_DEVICEDESC,
693 &DevInstData->regDataType,
694 NULL, 0,
695 &DevInstData->requiredSize);
696
697 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
698 {
699 DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
700 if (!DevInstData->buffer)
701 {
702 TRACE("HeapAlloc() failed\n");
703 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
704 }
705 else
706 {
707 ret = SetupDiGetDeviceRegistryPropertyW(
708 DevInstData->hDevInfo,
709 &DevInstData->devInfoData,
710 SPDRP_DEVICEDESC,
711 &DevInstData->regDataType,
712 DevInstData->buffer, DevInstData->requiredSize,
713 &DevInstData->requiredSize);
714 }
715 }
716 if (!ret)
717 {
718 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n",
719 GetLastError(), debugstr_w(InstanceId));
720 goto cleanup;
721 }
722
723 if (SetupDiGetDeviceRegistryPropertyW(
724 DevInstData->hDevInfo,
725 &DevInstData->devInfoData,
726 SPDRP_CONFIGFLAGS,
727 NULL,
728 (BYTE *)&config_flags,
729 sizeof(config_flags),
730 NULL))
731 {
732 if (config_flags & CONFIGFLAG_FAILEDINSTALL)
733 {
734 /* The device is disabled */
735 TRACE("Device is disabled\n");
736 retval = TRUE;
737 goto cleanup;
738 }
739 }
740
741 TRACE("Installing %s (%s)\n", debugstr_w((PCWSTR)DevInstData->buffer), debugstr_w(InstanceId));
742
743 /* Search driver in default location and removable devices */
744 if (!PrepareFoldersToScan(DevInstData, FALSE, FALSE, NULL))
745 {
746 TRACE("PrepareFoldersToScan() failed with error 0x%lx\n", GetLastError());
747 goto cleanup;
748 }
749 if (ScanFoldersForDriver(DevInstData))
750 {
751 /* Driver found ; install it */
752 retval = InstallCurrentDriver(DevInstData);
753 TRACE("InstallCurrentDriver() returned %d\n", retval);
754 if (retval && Show != SW_HIDE)
755 {
756 /* Should we display the 'Need to reboot' page? */
757 SP_DEVINSTALL_PARAMS installParams;
758 installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
759 if (SetupDiGetDeviceInstallParams(
760 DevInstData->hDevInfo,
761 &DevInstData->devInfoData,
762 &installParams))
763 {
764 if (installParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))
765 {
766 TRACE("Displaying 'Reboot' wizard page\n");
767 retval = DisplayWizard(DevInstData, hWndParent, IDD_NEEDREBOOT);
768 }
769 }
770 }
771 goto cleanup;
772 }
773 else if (Show == SW_HIDE)
774 {
775 /* We can't show the wizard. Fail the install */
776 TRACE("No wizard\n");
777 goto cleanup;
778 }
779
780 /* Prepare the wizard, and display it */
781 TRACE("Need to show install wizard\n");
782 retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
783
784 cleanup:
785 if (DevInstData)
786 {
787 if (DevInstData->devInfoData.cbSize != 0)
788 {
789 if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
790 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
791 }
792 if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
793 {
794 if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
795 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
796 }
797 HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
798 HeapFree(GetProcessHeap(), 0, DevInstData);
799 }
800
801 return retval;
802 }
803
804 /*
805 * @implemented
806 */
807 BOOL WINAPI
808 ClientSideInstallW(
809 IN HWND hWndOwner,
810 IN DWORD dwUnknownFlags,
811 IN LPWSTR lpNamedPipeName)
812 {
813 BOOL ReturnValue = FALSE;
814 BOOL ShowWizard;
815 DWORD BytesRead;
816 DWORD Value;
817 HANDLE hPipe = INVALID_HANDLE_VALUE;
818 PWSTR DeviceInstance = NULL;
819 PWSTR InstallEventName = NULL;
820
821 /* Open the pipe */
822 hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
823
824 if(hPipe == INVALID_HANDLE_VALUE)
825 {
826 ERR("CreateFileW failed with error %u\n", GetLastError());
827 goto cleanup;
828 }
829
830 /* Read the data. Some is just included for compatibility with Windows right now and not yet used by ReactOS.
831 See umpnpmgr for more details. */
832 if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
833 {
834 ERR("ReadFile failed with error %u\n", GetLastError());
835 goto cleanup;
836 }
837
838 InstallEventName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
839
840 if(!ReadFile(hPipe, InstallEventName, Value, &BytesRead, NULL))
841 {
842 ERR("ReadFile failed with error %u\n", GetLastError());
843 goto cleanup;
844 }
845
846 /* I couldn't figure out what the following value means under Windows XP.
847 Therefore I used it in umpnpmgr to pass the ShowWizard variable. */
848 if(!ReadFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesRead, NULL))
849 {
850 ERR("ReadFile failed with error %u\n", GetLastError());
851 goto cleanup;
852 }
853
854 /* Next one is again size in bytes of the following string */
855 if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
856 {
857 ERR("ReadFile failed with error %u\n", GetLastError());
858 goto cleanup;
859 }
860
861 DeviceInstance = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
862
863 if(!ReadFile(hPipe, DeviceInstance, Value, &BytesRead, NULL))
864 {
865 ERR("ReadFile failed with error %u\n", GetLastError());
866 goto cleanup;
867 }
868
869 ReturnValue = DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE);
870
871 cleanup:
872 if(hPipe != INVALID_HANDLE_VALUE)
873 CloseHandle(hPipe);
874
875 if(InstallEventName)
876 HeapFree(GetProcessHeap(), 0, InstallEventName);
877
878 if(DeviceInstance)
879 HeapFree(GetProcessHeap(), 0, DeviceInstance);
880
881 return ReturnValue;
882 }
883
884 BOOL WINAPI
885 DllMain(
886 IN HINSTANCE hInstance,
887 IN DWORD dwReason,
888 IN LPVOID lpReserved)
889 {
890 if (dwReason == DLL_PROCESS_ATTACH)
891 {
892 INITCOMMONCONTROLSEX InitControls;
893
894 DisableThreadLibraryCalls(hInstance);
895
896 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
897 InitControls.dwICC = ICC_PROGRESS_CLASS;
898 InitCommonControlsEx(&InitControls);
899 hDllInstance = hInstance;
900 }
901
902 return TRUE;
903 }