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