Sync with trunk r63831.
[reactos.git] / dll / win32 / newdev / newdev.c
1 /*
2 * New device installer (newdev.dll)
3 *
4 * Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
5 * 2005 Christoph von Wittich (Christoph@ActiveVB.de)
6 * 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 * @implemented
809 */
810 BOOL WINAPI
811 ClientSideInstallW(
812 IN HWND hWndOwner,
813 IN HINSTANCE hInstance,
814 IN LPWSTR lpNamedPipeName,
815 IN INT Show)
816 {
817 BOOL ReturnValue = FALSE;
818 BOOL ShowWizard;
819 DWORD BytesRead;
820 DWORD Value;
821 HANDLE hPipe = INVALID_HANDLE_VALUE;
822 PWSTR DeviceInstance = NULL;
823 PWSTR InstallEventName = NULL;
824
825 /* Open the pipe */
826 hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
827
828 if(hPipe == INVALID_HANDLE_VALUE)
829 {
830 ERR("CreateFileW failed with error %u\n", GetLastError());
831 goto cleanup;
832 }
833
834 /* Read the data. Some is just included for compatibility with Windows right now and not yet used by ReactOS.
835 See umpnpmgr for more details. */
836 if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
837 {
838 ERR("ReadFile failed with error %u\n", GetLastError());
839 goto cleanup;
840 }
841
842 InstallEventName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
843
844 if(!ReadFile(hPipe, InstallEventName, Value, &BytesRead, NULL))
845 {
846 ERR("ReadFile failed with error %u\n", GetLastError());
847 goto cleanup;
848 }
849
850 /* I couldn't figure out what the following value means under Windows XP.
851 Therefore I used it in umpnpmgr to pass the ShowWizard variable. */
852 if(!ReadFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesRead, NULL))
853 {
854 ERR("ReadFile failed with error %u\n", GetLastError());
855 goto cleanup;
856 }
857
858 /* Next one is again size in bytes of the following string */
859 if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
860 {
861 ERR("ReadFile failed with error %u\n", GetLastError());
862 goto cleanup;
863 }
864
865 DeviceInstance = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
866
867 if(!ReadFile(hPipe, DeviceInstance, Value, &BytesRead, NULL))
868 {
869 ERR("ReadFile failed with error %u\n", GetLastError());
870 goto cleanup;
871 }
872
873 ReturnValue = DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE);
874
875 cleanup:
876 if(hPipe != INVALID_HANDLE_VALUE)
877 CloseHandle(hPipe);
878
879 if(InstallEventName)
880 HeapFree(GetProcessHeap(), 0, InstallEventName);
881
882 if(DeviceInstance)
883 HeapFree(GetProcessHeap(), 0, DeviceInstance);
884
885 return ReturnValue;
886 }
887
888 BOOL WINAPI
889 DllMain(
890 IN HINSTANCE hInstance,
891 IN DWORD dwReason,
892 IN LPVOID lpReserved)
893 {
894 if (dwReason == DLL_PROCESS_ATTACH)
895 {
896 INITCOMMONCONTROLSEX InitControls;
897
898 DisableThreadLibraryCalls(hInstance);
899
900 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
901 InitControls.dwICC = ICC_PROGRESS_CLASS;
902 InitCommonControlsEx(&InitControls);
903 hDllInstance = hInstance;
904 }
905
906 return TRUE;
907 }