xref: /reactos/dll/win32/newdev/newdev.c (revision 40462c92)
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 ScanFoldersForDriver(
413     IN PDEVINSTDATA DevInstData)
414 {
415     BOOL result;
416 
417     /* Search in default location */
418     result = SearchDriver(DevInstData, NULL, NULL);
419 
420     if (DevInstData->CustomSearchPath)
421     {
422         /* Search only in specified paths */
423         /* We need to check all specified directories to be
424          * sure to find the best driver for the device.
425          */
426         LPCWSTR Path;
427         for (Path = DevInstData->CustomSearchPath; *Path != '\0'; Path += wcslen(Path) + 1)
428         {
429             TRACE("Search driver in %s\n", debugstr_w(Path));
430             if (wcslen(Path) == 2 && Path[1] == ':')
431             {
432                 if (SearchDriverRecursive(DevInstData, Path))
433                     result = TRUE;
434             }
435             else
436             {
437                 if (SearchDriver(DevInstData, Path, NULL))
438                     result = TRUE;
439             }
440         }
441     }
442 
443     return result;
444 }
445 
446 BOOL
447 PrepareFoldersToScan(
448     IN PDEVINSTDATA DevInstData,
449     IN BOOL IncludeRemovableDevices,
450     IN BOOL IncludeCustomPath,
451     IN HWND hwndCombo OPTIONAL)
452 {
453     WCHAR drive[] = {'?',':',0};
454     DWORD dwDrives = 0;
455     DWORD i;
456     UINT nType;
457     DWORD CustomTextLength = 0;
458     DWORD LengthNeeded = 0;
459     LPWSTR Buffer;
460 
461     /* Calculate length needed to store the search paths */
462     if (IncludeRemovableDevices)
463     {
464         dwDrives = GetLogicalDrives();
465         for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
466         {
467             if (dwDrives & i)
468             {
469                 nType = GetDriveTypeW(drive);
470                 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
471                 {
472                     LengthNeeded += 3;
473                 }
474             }
475         }
476     }
477     if (IncludeCustomPath)
478     {
479         CustomTextLength = 1 + ComboBox_GetTextLength(hwndCombo);
480         LengthNeeded += CustomTextLength;
481     }
482 
483     /* Allocate space for search paths */
484     HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath);
485     DevInstData->CustomSearchPath = Buffer = HeapAlloc(
486         GetProcessHeap(),
487         0,
488         (LengthNeeded + 1) * sizeof(WCHAR));
489     if (!Buffer)
490     {
491         TRACE("HeapAlloc() failed\n");
492         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
493         return FALSE;
494     }
495 
496     /* Fill search paths */
497     if (IncludeRemovableDevices)
498     {
499         for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
500         {
501             if (dwDrives & i)
502             {
503                 nType = GetDriveTypeW(drive);
504                 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
505                 {
506                     Buffer += 1 + swprintf(Buffer, drive);
507                 }
508             }
509         }
510     }
511     if (IncludeCustomPath)
512     {
513         Buffer += 1 + GetWindowTextW(hwndCombo, Buffer, CustomTextLength);
514     }
515     *Buffer = '\0';
516 
517     return TRUE;
518 }
519 
520 BOOL
521 InstallCurrentDriver(
522     IN PDEVINSTDATA DevInstData)
523 {
524     BOOL ret;
525 
526     TRACE("Installing driver %s: %s\n",
527         debugstr_w(DevInstData->drvInfoData.MfgName),
528         debugstr_w(DevInstData->drvInfoData.Description));
529 
530     ret = SetupDiCallClassInstaller(
531         DIF_SELECTBESTCOMPATDRV,
532         DevInstData->hDevInfo,
533         &DevInstData->devInfoData);
534     if (!ret)
535     {
536         TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%x\n", GetLastError());
537         return FALSE;
538     }
539 
540     ret = SetupDiCallClassInstaller(
541         DIF_ALLOW_INSTALL,
542         DevInstData->hDevInfo,
543         &DevInstData->devInfoData);
544     if (!ret)
545     {
546         TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%x\n", GetLastError());
547         return FALSE;
548     }
549 
550     ret = SetupDiCallClassInstaller(
551         DIF_NEWDEVICEWIZARD_PREANALYZE,
552         DevInstData->hDevInfo,
553         &DevInstData->devInfoData);
554     if (!ret)
555     {
556         TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%x\n", GetLastError());
557         return FALSE;
558     }
559 
560     ret = SetupDiCallClassInstaller(
561         DIF_NEWDEVICEWIZARD_POSTANALYZE,
562         DevInstData->hDevInfo,
563         &DevInstData->devInfoData);
564     if (!ret)
565     {
566         TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%x\n", GetLastError());
567         return FALSE;
568     }
569 
570     ret = SetupDiCallClassInstaller(
571         DIF_INSTALLDEVICEFILES,
572         DevInstData->hDevInfo,
573         &DevInstData->devInfoData);
574     if (!ret)
575     {
576         TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%x\n", GetLastError());
577         return FALSE;
578     }
579 
580     ret = SetupDiCallClassInstaller(
581         DIF_REGISTER_COINSTALLERS,
582         DevInstData->hDevInfo,
583         &DevInstData->devInfoData);
584     if (!ret)
585     {
586         TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%x\n", GetLastError());
587         return FALSE;
588     }
589 
590     ret = SetupDiCallClassInstaller(
591         DIF_INSTALLINTERFACES,
592         DevInstData->hDevInfo,
593         &DevInstData->devInfoData);
594     if (!ret)
595     {
596         TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%x\n", GetLastError());
597         return FALSE;
598     }
599 
600     ret = SetupDiCallClassInstaller(
601         DIF_INSTALLDEVICE,
602         DevInstData->hDevInfo,
603         &DevInstData->devInfoData);
604     if (!ret)
605     {
606         TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%x\n", GetLastError());
607         return FALSE;
608     }
609 
610     ret = SetupDiCallClassInstaller(
611         DIF_NEWDEVICEWIZARD_FINISHINSTALL,
612         DevInstData->hDevInfo,
613         &DevInstData->devInfoData);
614     if (!ret)
615     {
616         TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%x\n", GetLastError());
617         return FALSE;
618     }
619 
620     ret = SetupDiCallClassInstaller(
621         DIF_DESTROYPRIVATEDATA,
622         DevInstData->hDevInfo,
623         &DevInstData->devInfoData);
624     if (!ret)
625     {
626         TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%x\n", GetLastError());
627         return FALSE;
628     }
629 
630     return TRUE;
631 }
632 
633 /*
634 * @implemented
635 */
636 BOOL WINAPI
637 DevInstallW(
638     IN HWND hWndParent,
639     IN HINSTANCE hInstance,
640     IN LPCWSTR InstanceId,
641     IN INT Show)
642 {
643     PDEVINSTDATA DevInstData = NULL;
644     BOOL ret;
645     DWORD config_flags;
646     BOOL retval = FALSE;
647 
648     TRACE("(%p, %p, %s, %d)\n", hWndParent, hInstance, debugstr_w(InstanceId), Show);
649 
650     if (!IsUserAdmin())
651     {
652         /* XP kills the process... */
653         ExitProcess(ERROR_ACCESS_DENIED);
654     }
655 
656     DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
657     if (!DevInstData)
658     {
659         TRACE("HeapAlloc() failed\n");
660         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
661         goto cleanup;
662     }
663 
664     /* Clear devinst data */
665     ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
666     DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
667 
668     /* Fill devinst data */
669     DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
670     if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
671     {
672         TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError());
673         goto cleanup;
674     }
675 
676     DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
677     ret = SetupDiOpenDeviceInfoW(
678         DevInstData->hDevInfo,
679         InstanceId,
680         NULL,
681         0, /* Open flags */
682         &DevInstData->devInfoData);
683     if (!ret)
684     {
685         TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n",
686             GetLastError(), debugstr_w(InstanceId));
687         DevInstData->devInfoData.cbSize = 0;
688         goto cleanup;
689     }
690 
691     SetLastError(ERROR_GEN_FAILURE);
692     ret = SetupDiGetDeviceRegistryProperty(
693         DevInstData->hDevInfo,
694         &DevInstData->devInfoData,
695         SPDRP_DEVICEDESC,
696         &DevInstData->regDataType,
697         NULL, 0,
698         &DevInstData->requiredSize);
699 
700     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
701     {
702         DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
703         if (!DevInstData->buffer)
704         {
705             TRACE("HeapAlloc() failed\n");
706             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
707         }
708         else
709         {
710             ret = SetupDiGetDeviceRegistryPropertyW(
711                 DevInstData->hDevInfo,
712                 &DevInstData->devInfoData,
713                 SPDRP_DEVICEDESC,
714                 &DevInstData->regDataType,
715                 DevInstData->buffer, DevInstData->requiredSize,
716                 &DevInstData->requiredSize);
717         }
718     }
719     if (!ret)
720     {
721         TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n",
722             GetLastError(), debugstr_w(InstanceId));
723         goto cleanup;
724     }
725 
726     if (SetupDiGetDeviceRegistryPropertyW(
727         DevInstData->hDevInfo,
728         &DevInstData->devInfoData,
729         SPDRP_CONFIGFLAGS,
730         NULL,
731         (BYTE *)&config_flags,
732         sizeof(config_flags),
733         NULL))
734     {
735         if (config_flags & CONFIGFLAG_FAILEDINSTALL)
736         {
737             /* The device is disabled */
738             TRACE("Device is disabled\n");
739             retval = TRUE;
740             goto cleanup;
741         }
742     }
743 
744     TRACE("Installing %s (%s)\n", debugstr_w((PCWSTR)DevInstData->buffer), debugstr_w(InstanceId));
745 
746     /* Search driver in default location and removable devices */
747     if (!PrepareFoldersToScan(DevInstData, FALSE, FALSE, NULL))
748     {
749         TRACE("PrepareFoldersToScan() failed with error 0x%lx\n", GetLastError());
750         goto cleanup;
751     }
752     if (ScanFoldersForDriver(DevInstData))
753     {
754         /* Driver found ; install it */
755         retval = InstallCurrentDriver(DevInstData);
756         TRACE("InstallCurrentDriver() returned %d\n", retval);
757         if (retval && Show != SW_HIDE)
758         {
759             /* Should we display the 'Need to reboot' page? */
760             SP_DEVINSTALL_PARAMS installParams;
761             installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
762             if (SetupDiGetDeviceInstallParams(
763                 DevInstData->hDevInfo,
764                 &DevInstData->devInfoData,
765                 &installParams))
766             {
767                 if (installParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))
768                 {
769                     TRACE("Displaying 'Reboot' wizard page\n");
770                     retval = DisplayWizard(DevInstData, hWndParent, IDD_NEEDREBOOT);
771                 }
772             }
773         }
774         goto cleanup;
775     }
776     else if (Show == SW_HIDE)
777     {
778         /* We can't show the wizard. Fail the install */
779         TRACE("No wizard\n");
780         goto cleanup;
781     }
782 
783     /* Prepare the wizard, and display it */
784     TRACE("Need to show install wizard\n");
785     retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
786 
787 cleanup:
788     if (DevInstData)
789     {
790         if (DevInstData->devInfoData.cbSize != 0)
791         {
792             if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
793                 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
794         }
795         if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
796         {
797             if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
798                 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
799         }
800         HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
801         HeapFree(GetProcessHeap(), 0, DevInstData);
802     }
803 
804     return retval;
805 }
806 
807 
808 BOOL
809 WINAPI
810 InstallDevInstEx(
811     IN HWND hWndParent,
812     IN LPCWSTR InstanceId,
813     IN BOOL bUpdate,
814     OUT LPDWORD lpReboot,
815     IN DWORD Unknown)
816 {
817     PDEVINSTDATA DevInstData = NULL;
818     BOOL ret;
819     BOOL retval = FALSE;
820 
821     TRACE("InstllDevInstEx(%p, %s, %d, %p, %lx)\n",
822           hWndParent, debugstr_w(InstanceId), bUpdate, lpReboot, Unknown);
823 
824     DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
825     if (!DevInstData)
826     {
827         TRACE("HeapAlloc() failed\n");
828         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
829         goto cleanup;
830     }
831 
832     /* Clear devinst data */
833     ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
834     DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
835     DevInstData->bUpdate = bUpdate;
836 
837     /* Fill devinst data */
838     DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
839     if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
840     {
841         TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError());
842         goto cleanup;
843     }
844 
845     DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
846     ret = SetupDiOpenDeviceInfoW(
847         DevInstData->hDevInfo,
848         InstanceId,
849         NULL,
850         0, /* Open flags */
851         &DevInstData->devInfoData);
852     if (!ret)
853     {
854         TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n",
855             GetLastError(), debugstr_w(InstanceId));
856         DevInstData->devInfoData.cbSize = 0;
857         goto cleanup;
858     }
859 
860     SetLastError(ERROR_GEN_FAILURE);
861     ret = SetupDiGetDeviceRegistryProperty(
862         DevInstData->hDevInfo,
863         &DevInstData->devInfoData,
864         SPDRP_DEVICEDESC,
865         &DevInstData->regDataType,
866         NULL, 0,
867         &DevInstData->requiredSize);
868 
869     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
870     {
871         DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
872         if (!DevInstData->buffer)
873         {
874             TRACE("HeapAlloc() failed\n");
875             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
876         }
877         else
878         {
879             ret = SetupDiGetDeviceRegistryPropertyW(
880                 DevInstData->hDevInfo,
881                 &DevInstData->devInfoData,
882                 SPDRP_DEVICEDESC,
883                 &DevInstData->regDataType,
884                 DevInstData->buffer, DevInstData->requiredSize,
885                 &DevInstData->requiredSize);
886         }
887     }
888 
889     if (!ret)
890     {
891         TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n",
892             GetLastError(), debugstr_w(InstanceId));
893         goto cleanup;
894     }
895 
896     /* Prepare the wizard, and display it */
897     TRACE("Need to show install wizard\n");
898     retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
899 
900 cleanup:
901     if (DevInstData)
902     {
903         if (DevInstData->devInfoData.cbSize != 0)
904         {
905             if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
906                 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
907         }
908         if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
909         {
910             if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
911                 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
912         }
913         HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
914         HeapFree(GetProcessHeap(), 0, DevInstData);
915     }
916 
917     return retval;
918 }
919 
920 
921 /*
922  * @implemented
923  */
924 BOOL
925 WINAPI
926 InstallDevInst(
927     IN HWND hWndParent,
928     IN LPCWSTR InstanceId,
929     IN BOOL bUpdate,
930     OUT LPDWORD lpReboot)
931 {
932     return InstallDevInstEx(hWndParent, InstanceId, bUpdate, lpReboot, 0);
933 }
934 
935 
936 /*
937 * @implemented
938 */
939 BOOL WINAPI
940 ClientSideInstallW(
941     IN HWND hWndOwner,
942     IN HINSTANCE hInstance,
943     IN LPWSTR lpNamedPipeName,
944     IN INT Show)
945 {
946     BOOL ReturnValue = FALSE;
947     BOOL ShowWizard;
948     DWORD BytesRead;
949     DWORD Value;
950     HANDLE hPipe = INVALID_HANDLE_VALUE;
951     PWSTR DeviceInstance = NULL;
952     PWSTR InstallEventName = NULL;
953     HANDLE hInstallEvent;
954 
955     /* Open the pipe */
956     hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
957 
958     if(hPipe == INVALID_HANDLE_VALUE)
959     {
960         ERR("CreateFileW failed with error %u\n", GetLastError());
961         goto cleanup;
962     }
963 
964     /* Read the data. Some is just included for compatibility with Windows right now and not yet used by ReactOS.
965        See umpnpmgr for more details. */
966     if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
967     {
968         ERR("ReadFile failed with error %u\n", GetLastError());
969         goto cleanup;
970     }
971 
972     InstallEventName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
973 
974     if(!ReadFile(hPipe, InstallEventName, Value, &BytesRead, NULL))
975     {
976         ERR("ReadFile failed with error %u\n", GetLastError());
977         goto cleanup;
978     }
979 
980     /* I couldn't figure out what the following value means under Windows XP.
981        Therefore I used it in umpnpmgr to pass the ShowWizard variable. */
982     if(!ReadFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesRead, NULL))
983     {
984         ERR("ReadFile failed with error %u\n", GetLastError());
985         goto cleanup;
986     }
987 
988     /* Next one is again size in bytes of the following string */
989     if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
990     {
991         ERR("ReadFile failed with error %u\n", GetLastError());
992         goto cleanup;
993     }
994 
995     DeviceInstance = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
996 
997     if(!ReadFile(hPipe, DeviceInstance, Value, &BytesRead, NULL))
998     {
999         ERR("ReadFile failed with error %u\n", GetLastError());
1000         goto cleanup;
1001     }
1002 
1003     ReturnValue = DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE);
1004     if(!ReturnValue)
1005     {
1006         ERR("DevInstallW failed with error %lu\n", GetLastError());
1007         goto cleanup;
1008     }
1009 
1010     hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
1011     if(!hInstallEvent)
1012     {
1013         TRACE("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
1014         goto cleanup;
1015     }
1016 
1017     SetEvent(hInstallEvent);
1018     CloseHandle(hInstallEvent);
1019 
1020 cleanup:
1021     if(hPipe != INVALID_HANDLE_VALUE)
1022         CloseHandle(hPipe);
1023 
1024     if(InstallEventName)
1025         HeapFree(GetProcessHeap(), 0, InstallEventName);
1026 
1027     if(DeviceInstance)
1028         HeapFree(GetProcessHeap(), 0, DeviceInstance);
1029 
1030     return ReturnValue;
1031 }
1032 
1033 BOOL WINAPI
1034 DllMain(
1035     IN HINSTANCE hInstance,
1036     IN DWORD dwReason,
1037     IN LPVOID lpReserved)
1038 {
1039     if (dwReason == DLL_PROCESS_ATTACH)
1040     {
1041         INITCOMMONCONTROLSEX InitControls;
1042 
1043         DisableThreadLibraryCalls(hInstance);
1044 
1045         InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
1046         InitControls.dwICC = ICC_PROGRESS_CLASS;
1047         InitCommonControlsEx(&InitControls);
1048         hDllInstance = hInstance;
1049     }
1050 
1051     return TRUE;
1052 }
1053