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