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