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