xref: /reactos/dll/win32/newdev/newdev.c (revision 14d3b53c)
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 #include <stdio.h>
26 #include <winnls.h>
27 
28 /* Global variables */
29 HINSTANCE hDllInstance;
30 
31 static BOOL
32 SearchDriver(
33     IN PDEVINSTDATA DevInstData,
34     IN LPCWSTR Directory OPTIONAL,
35     IN LPCWSTR InfFile OPTIONAL);
36 
37 /*
38 * @implemented
39 */
40 BOOL WINAPI
41 UpdateDriverForPlugAndPlayDevicesW(
42     IN HWND hwndParent,
43     IN LPCWSTR HardwareId,
44     IN LPCWSTR FullInfPath,
45     IN DWORD InstallFlags,
46     OUT PBOOL bRebootRequired OPTIONAL)
47 {
48     DEVINSTDATA DevInstData;
49     DWORD i;
50     LPWSTR Buffer = NULL;
51     DWORD BufferSize;
52     LPCWSTR CurrentHardwareId; /* Pointer into Buffer */
53     BOOL FoundHardwareId, FoundAtLeastOneDevice = FALSE;
54     BOOL ret = FALSE;
55 
56     DevInstData.hDevInfo = INVALID_HANDLE_VALUE;
57 
58     TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %s %s 0x%x %p)\n",
59         hwndParent, debugstr_w(HardwareId), debugstr_w(FullInfPath), InstallFlags, bRebootRequired);
60 
61     /* FIXME: InstallFlags bRebootRequired ignored! */
62 
63     /* Check flags */
64     if (InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE))
65     {
66         TRACE("Unknown flags: 0x%08lx\n", InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE));
67         SetLastError(ERROR_INVALID_FLAGS);
68         goto cleanup;
69     }
70 
71     /* Enumerate all devices of the system */
72     DevInstData.hDevInfo = SetupDiGetClassDevsW(NULL, NULL, hwndParent, DIGCF_ALLCLASSES | DIGCF_PRESENT);
73     if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE)
74         goto cleanup;
75     DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
76     for (i = 0; ; i++)
77     {
78         if (!SetupDiEnumDeviceInfo(DevInstData.hDevInfo, i, &DevInstData.devInfoData))
79         {
80             if (GetLastError() != ERROR_NO_MORE_ITEMS)
81             {
82                 TRACE("SetupDiEnumDeviceInfo() failed with error 0x%x\n", GetLastError());
83                 goto cleanup;
84             }
85             /* This error was expected */
86             break;
87         }
88 
89         /* Get Hardware ID */
90         HeapFree(GetProcessHeap(), 0, Buffer);
91         Buffer = NULL;
92         BufferSize = 0;
93         while (!SetupDiGetDeviceRegistryPropertyW(
94             DevInstData.hDevInfo,
95             &DevInstData.devInfoData,
96             SPDRP_HARDWAREID,
97             NULL,
98             (PBYTE)Buffer,
99             BufferSize,
100             &BufferSize))
101         {
102             if (GetLastError() == ERROR_FILE_NOT_FOUND)
103             {
104                 Buffer = NULL;
105                 break;
106             }
107             else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
108             {
109                 TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%x\n", GetLastError());
110                 goto cleanup;
111             }
112             /* This error was expected */
113             HeapFree(GetProcessHeap(), 0, Buffer);
114             Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
115             if (!Buffer)
116             {
117                 TRACE("HeapAlloc() failed\n", GetLastError());
118                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
119                 goto cleanup;
120             }
121         }
122         if (Buffer == NULL)
123             continue;
124 
125         /* Check if we match the given hardware ID */
126         FoundHardwareId = FALSE;
127         for (CurrentHardwareId = Buffer; *CurrentHardwareId != UNICODE_NULL; CurrentHardwareId += wcslen(CurrentHardwareId) + 1)
128         {
129             if (wcscmp(CurrentHardwareId, HardwareId) == 0)
130             {
131                 FoundHardwareId = TRUE;
132                 break;
133             }
134         }
135         if (!FoundHardwareId)
136             continue;
137 
138         /* We need to try to update the driver of this device */
139 
140         /* Get Instance ID */
141         HeapFree(GetProcessHeap(), 0, Buffer);
142         Buffer = NULL;
143         if (SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, NULL, 0, &BufferSize))
144         {
145             /* Error, as the output buffer should be too small */
146             SetLastError(ERROR_GEN_FAILURE);
147             goto cleanup;
148         }
149         else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
150         {
151             TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError());
152             goto cleanup;
153         }
154         else if ((Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize * sizeof(WCHAR))) == NULL)
155         {
156             TRACE("HeapAlloc() failed\n", GetLastError());
157             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
158             goto cleanup;
159         }
160         else if (!SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, Buffer, BufferSize, NULL))
161         {
162             TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError());
163             goto cleanup;
164         }
165         TRACE("Trying to update the driver of %s\n", debugstr_w(Buffer));
166 
167         /* Search driver in the specified .inf file */
168         if (!SearchDriver(&DevInstData, NULL, FullInfPath))
169         {
170             TRACE("SearchDriver() failed with error 0x%x\n", GetLastError());
171             continue;
172         }
173 
174         /* FIXME: HACK! We shouldn't check of ERROR_PRIVILEGE_NOT_HELD */
175         //if (!InstallCurrentDriver(&DevInstData))
176         if (!InstallCurrentDriver(&DevInstData) && GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
177         {
178             TRACE("InstallCurrentDriver() failed with error 0x%x\n", GetLastError());
179             continue;
180         }
181 
182         FoundAtLeastOneDevice = TRUE;
183     }
184 
185     if (FoundAtLeastOneDevice)
186     {
187         SetLastError(NO_ERROR);
188         ret = TRUE;
189     }
190     else
191     {
192         TRACE("No device found with HardwareID %s\n", debugstr_w(HardwareId));
193         SetLastError(ERROR_NO_SUCH_DEVINST);
194     }
195 
196 cleanup:
197     if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE)
198         SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo);
199     HeapFree(GetProcessHeap(), 0, Buffer);
200     return ret;
201 }
202 
203 /*
204 * @implemented
205 */
206 BOOL WINAPI
207 UpdateDriverForPlugAndPlayDevicesA(
208     IN HWND hwndParent,
209     IN LPCSTR HardwareId,
210     IN LPCSTR FullInfPath,
211     IN DWORD InstallFlags,
212     OUT PBOOL bRebootRequired OPTIONAL)
213 {
214     BOOL Result;
215     LPWSTR HardwareIdW = NULL;
216     LPWSTR FullInfPathW = NULL;
217 
218     int len = MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, NULL, 0);
219     HardwareIdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
220     if (!HardwareIdW)
221     {
222         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
223         return FALSE;
224     }
225     MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, HardwareIdW, len);
226 
227     len = MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, NULL, 0);
228     FullInfPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
229     if (!FullInfPathW)
230     {
231         HeapFree(GetProcessHeap(), 0, HardwareIdW);
232         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
233         return FALSE;
234     }
235     MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, FullInfPathW, len);
236 
237     Result = UpdateDriverForPlugAndPlayDevicesW(
238         hwndParent,
239         HardwareIdW,
240         FullInfPathW,
241         InstallFlags,
242         bRebootRequired);
243 
244     HeapFree(GetProcessHeap(), 0, HardwareIdW);
245     HeapFree(GetProcessHeap(), 0, FullInfPathW);
246 
247     return Result;
248 }
249 
250 /* Directory and InfFile MUST NOT be specified simultaneously */
251 static BOOL
252 SearchDriver(
253     IN PDEVINSTDATA DevInstData,
254     IN LPCWSTR Directory OPTIONAL,
255     IN LPCWSTR InfFile OPTIONAL)
256 {
257     SP_DEVINSTALL_PARAMS_W DevInstallParams = {0,};
258     BOOL ret;
259 
260     DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
261     if (!SetupDiGetDeviceInstallParamsW(DevInstData->hDevInfo, &DevInstData->devInfoData, &DevInstallParams))
262     {
263         TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%x\n", GetLastError());
264         return FALSE;
265     }
266     DevInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
267 
268     if (InfFile)
269     {
270         DevInstallParams.Flags |= DI_ENUMSINGLEINF;
271         wcsncpy(DevInstallParams.DriverPath, InfFile, MAX_PATH);
272     }
273     else if (Directory)
274     {
275         DevInstallParams.Flags &= ~DI_ENUMSINGLEINF;
276         wcsncpy(DevInstallParams.DriverPath, Directory, MAX_PATH);
277     }
278     else
279     {
280         DevInstallParams.Flags &= ~DI_ENUMSINGLEINF;
281         *DevInstallParams.DriverPath = '\0';
282     }
283 
284     ret = SetupDiSetDeviceInstallParamsW(
285         DevInstData->hDevInfo,
286         &DevInstData->devInfoData,
287         &DevInstallParams);
288     if (!ret)
289     {
290         TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%x\n", GetLastError());
291         return FALSE;
292     }
293 
294     ret = SetupDiBuildDriverInfoList(
295         DevInstData->hDevInfo,
296         &DevInstData->devInfoData,
297         SPDIT_COMPATDRIVER);
298     if (!ret)
299     {
300         TRACE("SetupDiBuildDriverInfoList() failed with error 0x%x\n", GetLastError());
301         return FALSE;
302     }
303 
304     DevInstData->drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
305     ret = SetupDiEnumDriverInfoW(
306         DevInstData->hDevInfo,
307         &DevInstData->devInfoData,
308         SPDIT_COMPATDRIVER,
309         0,
310         &DevInstData->drvInfoData);
311     if (!ret)
312     {
313         if (GetLastError() == ERROR_NO_MORE_ITEMS)
314             return FALSE;
315         TRACE("SetupDiEnumDriverInfo() failed with error 0x%x\n", GetLastError());
316         return FALSE;
317     }
318 
319     return TRUE;
320 }
321 
322 static BOOL
323 IsDots(IN LPCWSTR str)
324 {
325     if(wcscmp(str, L".") && wcscmp(str, L"..")) return FALSE;
326     return TRUE;
327 }
328 
329 static LPCWSTR
330 GetFileExt(IN LPWSTR FileName)
331 {
332     LPCWSTR Dot;
333 
334     Dot = wcsrchr(FileName, '.');
335     if (!Dot)
336         return L"";
337 
338     return Dot;
339 }
340 
341 static BOOL
342 SearchDriverRecursive(
343     IN PDEVINSTDATA DevInstData,
344     IN LPCWSTR Path)
345 {
346     WIN32_FIND_DATAW wfd;
347     WCHAR DirPath[MAX_PATH];
348     WCHAR FileName[MAX_PATH];
349     WCHAR FullPath[MAX_PATH];
350     WCHAR LastDirPath[MAX_PATH] = L"";
351     WCHAR PathWithPattern[MAX_PATH];
352     BOOL ok = TRUE;
353     BOOL retval = FALSE;
354     HANDLE hFindFile = INVALID_HANDLE_VALUE;
355 
356     wcscpy(DirPath, Path);
357 
358     if (DirPath[wcslen(DirPath) - 1] != '\\')
359         wcscat(DirPath, L"\\");
360 
361     wcscpy(PathWithPattern, DirPath);
362     wcscat(PathWithPattern, L"*");
363 
364     for (hFindFile = FindFirstFileW(PathWithPattern, &wfd);
365         ok && hFindFile != INVALID_HANDLE_VALUE;
366         ok = FindNextFileW(hFindFile, &wfd))
367     {
368 
369         wcscpy(FileName, wfd.cFileName);
370         if (IsDots(FileName))
371             continue;
372 
373         if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
374         {
375             /* Recursive search */
376             wcscpy(FullPath, DirPath);
377             wcscat(FullPath, FileName);
378             if (SearchDriverRecursive(DevInstData, FullPath))
379             {
380                 retval = TRUE;
381                 /* We continue the search for a better driver */
382             }
383         }
384         else
385         {
386             LPCWSTR pszExtension = GetFileExt(FileName);
387 
388             if ((_wcsicmp(pszExtension, L".inf") == 0) && (wcscmp(LastDirPath, DirPath) != 0))
389             {
390                 wcscpy(LastDirPath, DirPath);
391 
392                 if (wcslen(DirPath) > MAX_PATH)
393                     /* Path is too long to be searched */
394                     continue;
395 
396                 if (SearchDriver(DevInstData, DirPath, NULL))
397                 {
398                     retval = TRUE;
399                     /* We continue the search for a better driver */
400                 }
401 
402             }
403         }
404     }
405 
406     if (hFindFile != INVALID_HANDLE_VALUE)
407         FindClose(hFindFile);
408     return retval;
409 }
410 
411 BOOL
412 CheckBestDriver(
413     _In_ PDEVINSTDATA DevInstData,
414     _In_ PCWSTR pszDir)
415 {
416     return SearchDriverRecursive(DevInstData, pszDir);
417 }
418 
419 BOOL
420 ScanFoldersForDriver(
421     IN PDEVINSTDATA DevInstData)
422 {
423     BOOL result;
424 
425     /* Search in default location */
426     result = SearchDriver(DevInstData, NULL, NULL);
427 
428     if (DevInstData->CustomSearchPath)
429     {
430         /* Search only in specified paths */
431         /* We need to check all specified directories to be
432          * sure to find the best driver for the device.
433          */
434         LPCWSTR Path;
435         for (Path = DevInstData->CustomSearchPath; *Path != '\0'; Path += wcslen(Path) + 1)
436         {
437             TRACE("Search driver in %s\n", debugstr_w(Path));
438             if (wcslen(Path) == 2 && Path[1] == ':')
439             {
440                 if (SearchDriverRecursive(DevInstData, Path))
441                     result = TRUE;
442             }
443             else
444             {
445                 if (SearchDriver(DevInstData, Path, NULL))
446                     result = TRUE;
447             }
448         }
449     }
450 
451     return result;
452 }
453 
454 BOOL
455 PrepareFoldersToScan(
456     IN PDEVINSTDATA DevInstData,
457     IN BOOL IncludeRemovableDevices,
458     IN BOOL IncludeCustomPath,
459     IN HWND hwndCombo OPTIONAL)
460 {
461     WCHAR drive[] = {'?',':',0};
462     DWORD dwDrives = 0;
463     DWORD i;
464     UINT nType;
465     DWORD CustomTextLength = 0;
466     DWORD LengthNeeded = 0;
467     LPWSTR Buffer;
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 = GetDriveTypeW(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(WCHAR));
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 = GetDriveTypeW(drive);
512                 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
513                 {
514                     Buffer += 1 + swprintf(Buffer, drive);
515                 }
516             }
517         }
518     }
519     if (IncludeCustomPath)
520     {
521         Buffer += 1 + GetWindowTextW(hwndCombo, Buffer, CustomTextLength);
522     }
523     *Buffer = '\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",
535         debugstr_w(DevInstData->drvInfoData.MfgName),
536         debugstr_w(DevInstData->drvInfoData.Description));
537 
538     ret = SetupDiCallClassInstaller(
539         DIF_SELECTBESTCOMPATDRV,
540         DevInstData->hDevInfo,
541         &DevInstData->devInfoData);
542     if (!ret)
543     {
544         TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%x\n", GetLastError());
545         return FALSE;
546     }
547 
548     ret = SetupDiCallClassInstaller(
549         DIF_ALLOW_INSTALL,
550         DevInstData->hDevInfo,
551         &DevInstData->devInfoData);
552     if (!ret)
553     {
554         TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%x\n", GetLastError());
555         return FALSE;
556     }
557 
558     ret = SetupDiCallClassInstaller(
559         DIF_NEWDEVICEWIZARD_PREANALYZE,
560         DevInstData->hDevInfo,
561         &DevInstData->devInfoData);
562     if (!ret)
563     {
564         TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%x\n", GetLastError());
565         return FALSE;
566     }
567 
568     ret = SetupDiCallClassInstaller(
569         DIF_NEWDEVICEWIZARD_POSTANALYZE,
570         DevInstData->hDevInfo,
571         &DevInstData->devInfoData);
572     if (!ret)
573     {
574         TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%x\n", GetLastError());
575         return FALSE;
576     }
577 
578     ret = SetupDiCallClassInstaller(
579         DIF_INSTALLDEVICEFILES,
580         DevInstData->hDevInfo,
581         &DevInstData->devInfoData);
582     if (!ret)
583     {
584         TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%x\n", GetLastError());
585         return FALSE;
586     }
587 
588     ret = SetupDiCallClassInstaller(
589         DIF_REGISTER_COINSTALLERS,
590         DevInstData->hDevInfo,
591         &DevInstData->devInfoData);
592     if (!ret)
593     {
594         TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%x\n", GetLastError());
595         return FALSE;
596     }
597 
598     ret = SetupDiCallClassInstaller(
599         DIF_INSTALLINTERFACES,
600         DevInstData->hDevInfo,
601         &DevInstData->devInfoData);
602     if (!ret)
603     {
604         TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%x\n", GetLastError());
605         return FALSE;
606     }
607 
608     ret = SetupDiCallClassInstaller(
609         DIF_INSTALLDEVICE,
610         DevInstData->hDevInfo,
611         &DevInstData->devInfoData);
612     if (!ret)
613     {
614         TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%x\n", GetLastError());
615         return FALSE;
616     }
617 
618     ret = SetupDiCallClassInstaller(
619         DIF_NEWDEVICEWIZARD_FINISHINSTALL,
620         DevInstData->hDevInfo,
621         &DevInstData->devInfoData);
622     if (!ret)
623     {
624         TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%x\n", GetLastError());
625         return FALSE;
626     }
627 
628     ret = SetupDiCallClassInstaller(
629         DIF_DESTROYPRIVATEDATA,
630         DevInstData->hDevInfo,
631         &DevInstData->devInfoData);
632     if (!ret)
633     {
634         TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%x\n", GetLastError());
635         return FALSE;
636     }
637 
638     return TRUE;
639 }
640 
641 /*
642 * @implemented
643 */
644 BOOL WINAPI
645 DevInstallW(
646     IN HWND hWndParent,
647     IN HINSTANCE hInstance,
648     IN LPCWSTR InstanceId,
649     IN INT Show)
650 {
651     PDEVINSTDATA DevInstData = NULL;
652     BOOL ret;
653     DWORD config_flags;
654     BOOL retval = FALSE;
655 
656     TRACE("(%p, %p, %s, %d)\n", hWndParent, hInstance, debugstr_w(InstanceId), Show);
657 
658     if (!IsUserAdmin())
659     {
660         /* XP kills the process... */
661         ExitProcess(ERROR_ACCESS_DENIED);
662     }
663 
664     DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
665     if (!DevInstData)
666     {
667         TRACE("HeapAlloc() failed\n");
668         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
669         goto cleanup;
670     }
671 
672     /* Clear devinst data */
673     ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
674     DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
675 
676     /* Fill devinst data */
677     DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
678     if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
679     {
680         TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError());
681         goto cleanup;
682     }
683 
684     DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
685     ret = SetupDiOpenDeviceInfoW(
686         DevInstData->hDevInfo,
687         InstanceId,
688         NULL,
689         0, /* Open flags */
690         &DevInstData->devInfoData);
691     if (!ret)
692     {
693         TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n",
694             GetLastError(), debugstr_w(InstanceId));
695         DevInstData->devInfoData.cbSize = 0;
696         goto cleanup;
697     }
698 
699     SetLastError(ERROR_GEN_FAILURE);
700     ret = SetupDiGetDeviceRegistryProperty(
701         DevInstData->hDevInfo,
702         &DevInstData->devInfoData,
703         SPDRP_DEVICEDESC,
704         &DevInstData->regDataType,
705         NULL, 0,
706         &DevInstData->requiredSize);
707 
708     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
709     {
710         DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
711         if (!DevInstData->buffer)
712         {
713             TRACE("HeapAlloc() failed\n");
714             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
715         }
716         else
717         {
718             ret = SetupDiGetDeviceRegistryPropertyW(
719                 DevInstData->hDevInfo,
720                 &DevInstData->devInfoData,
721                 SPDRP_DEVICEDESC,
722                 &DevInstData->regDataType,
723                 DevInstData->buffer, DevInstData->requiredSize,
724                 &DevInstData->requiredSize);
725         }
726     }
727     if (!ret)
728     {
729         TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n",
730             GetLastError(), debugstr_w(InstanceId));
731         goto cleanup;
732     }
733 
734     if (SetupDiGetDeviceRegistryPropertyW(
735         DevInstData->hDevInfo,
736         &DevInstData->devInfoData,
737         SPDRP_CONFIGFLAGS,
738         NULL,
739         (BYTE *)&config_flags,
740         sizeof(config_flags),
741         NULL))
742     {
743         if (config_flags & CONFIGFLAG_FAILEDINSTALL)
744         {
745             /* The device is disabled */
746             TRACE("Device is disabled\n");
747             retval = TRUE;
748             goto cleanup;
749         }
750     }
751 
752     TRACE("Installing %s (%s)\n", debugstr_w((PCWSTR)DevInstData->buffer), debugstr_w(InstanceId));
753 
754     /* Search driver in default location and removable devices */
755     if (!PrepareFoldersToScan(DevInstData, FALSE, FALSE, NULL))
756     {
757         TRACE("PrepareFoldersToScan() failed with error 0x%lx\n", GetLastError());
758         goto cleanup;
759     }
760     if (ScanFoldersForDriver(DevInstData))
761     {
762         /* Driver found ; install it */
763         retval = InstallCurrentDriver(DevInstData);
764         TRACE("InstallCurrentDriver() returned %d\n", retval);
765         if (retval && Show != SW_HIDE)
766         {
767             /* Should we display the 'Need to reboot' page? */
768             SP_DEVINSTALL_PARAMS installParams;
769             installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
770             if (SetupDiGetDeviceInstallParams(
771                 DevInstData->hDevInfo,
772                 &DevInstData->devInfoData,
773                 &installParams))
774             {
775                 if (installParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))
776                 {
777                     TRACE("Displaying 'Reboot' wizard page\n");
778                     retval = DisplayWizard(DevInstData, hWndParent, IDD_NEEDREBOOT);
779                 }
780             }
781         }
782         goto cleanup;
783     }
784     else if (Show == SW_HIDE)
785     {
786         /* We can't show the wizard. Fail the install */
787         TRACE("No wizard\n");
788         goto cleanup;
789     }
790 
791     /* Prepare the wizard, and display it */
792     TRACE("Need to show install wizard\n");
793     retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
794 
795 cleanup:
796     if (DevInstData)
797     {
798         if (DevInstData->devInfoData.cbSize != 0)
799         {
800             if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
801                 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
802         }
803         if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
804         {
805             if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
806                 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
807         }
808         HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
809         HeapFree(GetProcessHeap(), 0, DevInstData);
810     }
811 
812     return retval;
813 }
814 
815 
816 BOOL
817 WINAPI
818 InstallDevInstEx(
819     IN HWND hWndParent,
820     IN LPCWSTR InstanceId,
821     IN BOOL bUpdate,
822     OUT LPDWORD lpReboot,
823     IN DWORD Unknown)
824 {
825     PDEVINSTDATA DevInstData = NULL;
826     BOOL ret;
827     BOOL retval = FALSE;
828 
829     TRACE("InstllDevInstEx(%p, %s, %d, %p, %lx)\n",
830           hWndParent, debugstr_w(InstanceId), bUpdate, lpReboot, Unknown);
831 
832     DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
833     if (!DevInstData)
834     {
835         TRACE("HeapAlloc() failed\n");
836         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
837         goto cleanup;
838     }
839 
840     /* Clear devinst data */
841     ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
842     DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
843     DevInstData->bUpdate = bUpdate;
844 
845     /* Fill devinst data */
846     DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
847     if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
848     {
849         TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError());
850         goto cleanup;
851     }
852 
853     DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
854     ret = SetupDiOpenDeviceInfoW(
855         DevInstData->hDevInfo,
856         InstanceId,
857         NULL,
858         0, /* Open flags */
859         &DevInstData->devInfoData);
860     if (!ret)
861     {
862         TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n",
863             GetLastError(), debugstr_w(InstanceId));
864         DevInstData->devInfoData.cbSize = 0;
865         goto cleanup;
866     }
867 
868     SetLastError(ERROR_GEN_FAILURE);
869     ret = SetupDiGetDeviceRegistryProperty(
870         DevInstData->hDevInfo,
871         &DevInstData->devInfoData,
872         SPDRP_DEVICEDESC,
873         &DevInstData->regDataType,
874         NULL, 0,
875         &DevInstData->requiredSize);
876 
877     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
878     {
879         DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
880         if (!DevInstData->buffer)
881         {
882             TRACE("HeapAlloc() failed\n");
883             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
884         }
885         else
886         {
887             ret = SetupDiGetDeviceRegistryPropertyW(
888                 DevInstData->hDevInfo,
889                 &DevInstData->devInfoData,
890                 SPDRP_DEVICEDESC,
891                 &DevInstData->regDataType,
892                 DevInstData->buffer, DevInstData->requiredSize,
893                 &DevInstData->requiredSize);
894         }
895     }
896 
897     if (!ret)
898     {
899         TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n",
900             GetLastError(), debugstr_w(InstanceId));
901         goto cleanup;
902     }
903 
904     /* Prepare the wizard, and display it */
905     TRACE("Need to show install wizard\n");
906     retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
907 
908 cleanup:
909     if (DevInstData)
910     {
911         if (DevInstData->devInfoData.cbSize != 0)
912         {
913             if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
914                 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
915         }
916         if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
917         {
918             if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
919                 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
920         }
921         HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
922         HeapFree(GetProcessHeap(), 0, DevInstData);
923     }
924 
925     return retval;
926 }
927 
928 
929 /*
930  * @implemented
931  */
932 BOOL
933 WINAPI
934 InstallDevInst(
935     IN HWND hWndParent,
936     IN LPCWSTR InstanceId,
937     IN BOOL bUpdate,
938     OUT LPDWORD lpReboot)
939 {
940     return InstallDevInstEx(hWndParent, InstanceId, bUpdate, lpReboot, 0);
941 }
942 
943 
944 /*
945 * @implemented
946 */
947 BOOL WINAPI
948 ClientSideInstallW(
949     IN HWND hWndOwner,
950     IN HINSTANCE hInstance,
951     IN LPWSTR lpNamedPipeName,
952     IN INT Show)
953 {
954     BOOL ReturnValue = FALSE;
955     BOOL ShowWizard;
956     DWORD BytesRead;
957     DWORD Value;
958     HANDLE hPipe = INVALID_HANDLE_VALUE;
959     PWSTR DeviceInstance = NULL;
960     PWSTR InstallEventName = NULL;
961     HANDLE hInstallEvent;
962 
963     /* Open the pipe */
964     hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
965 
966     if(hPipe == INVALID_HANDLE_VALUE)
967     {
968         ERR("CreateFileW failed with error %u\n", GetLastError());
969         goto cleanup;
970     }
971 
972     /* Read the data. Some is just included for compatibility with Windows right now and not yet used by ReactOS.
973        See umpnpmgr for more details. */
974     if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
975     {
976         ERR("ReadFile failed with error %u\n", GetLastError());
977         goto cleanup;
978     }
979 
980     InstallEventName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
981 
982     if(!ReadFile(hPipe, InstallEventName, Value, &BytesRead, NULL))
983     {
984         ERR("ReadFile failed with error %u\n", GetLastError());
985         goto cleanup;
986     }
987 
988     /* I couldn't figure out what the following value means under Windows XP.
989        Therefore I used it in umpnpmgr to pass the ShowWizard variable. */
990     if(!ReadFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesRead, NULL))
991     {
992         ERR("ReadFile failed with error %u\n", GetLastError());
993         goto cleanup;
994     }
995 
996     /* Next one is again size in bytes of the following string */
997     if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
998     {
999         ERR("ReadFile failed with error %u\n", GetLastError());
1000         goto cleanup;
1001     }
1002 
1003     DeviceInstance = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
1004 
1005     if(!ReadFile(hPipe, DeviceInstance, Value, &BytesRead, NULL))
1006     {
1007         ERR("ReadFile failed with error %u\n", GetLastError());
1008         goto cleanup;
1009     }
1010 
1011     ReturnValue = DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE);
1012     if(!ReturnValue)
1013     {
1014         ERR("DevInstallW failed with error %lu\n", GetLastError());
1015         goto cleanup;
1016     }
1017 
1018     hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
1019     if(!hInstallEvent)
1020     {
1021         TRACE("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
1022         goto cleanup;
1023     }
1024 
1025     SetEvent(hInstallEvent);
1026     CloseHandle(hInstallEvent);
1027 
1028 cleanup:
1029     if(hPipe != INVALID_HANDLE_VALUE)
1030         CloseHandle(hPipe);
1031 
1032     if(InstallEventName)
1033         HeapFree(GetProcessHeap(), 0, InstallEventName);
1034 
1035     if(DeviceInstance)
1036         HeapFree(GetProcessHeap(), 0, DeviceInstance);
1037 
1038     return ReturnValue;
1039 }
1040 
1041 BOOL WINAPI
1042 DllMain(
1043     IN HINSTANCE hInstance,
1044     IN DWORD dwReason,
1045     IN LPVOID lpReserved)
1046 {
1047     if (dwReason == DLL_PROCESS_ATTACH)
1048     {
1049         INITCOMMONCONTROLSEX InitControls;
1050 
1051         DisableThreadLibraryCalls(hInstance);
1052 
1053         InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
1054         InitControls.dwICC = ICC_PROGRESS_CLASS;
1055         InitCommonControlsEx(&InitControls);
1056         hDllInstance = hInstance;
1057     }
1058 
1059     return TRUE;
1060 }
1061