7019c5d1f28b6500452bcb938e74ab9326afc03a
[reactos.git] / reactos / 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 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #define YDEBUG
23 #include "newdev.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(newdev);
26
27 /* Global variables */
28 HINSTANCE hDllInstance;
29
30 /*
31 * @implemented
32 */
33 BOOL WINAPI
34 UpdateDriverForPlugAndPlayDevicesW(
35 IN HWND hwndParent,
36 IN LPCWSTR HardwareId,
37 IN LPCWSTR FullInfPath,
38 IN DWORD InstallFlags,
39 OUT PBOOL bRebootRequired OPTIONAL)
40 {
41 DEVINSTDATA DevInstData;
42 DWORD i;
43 LPWSTR Buffer = NULL;
44 DWORD BufferSize;
45 LPCWSTR CurrentHardwareId; /* Pointer into Buffer */
46 BOOL FoundHardwareId, FoundAtLeastOneDevice = FALSE;
47 BOOL ret = FALSE;
48
49 DevInstData.hDevInfo = INVALID_HANDLE_VALUE;
50
51 TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %S %S 0x%lx %p)\n",
52 hwndParent, HardwareId, FullInfPath, InstallFlags, bRebootRequired);
53
54 /* FIXME: InstallFlags bRebootRequired ignored! */
55
56 /* Check flags */
57 /* FIXME: if (InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE))
58 {
59 DPRINT("Unknown flags: 0x%08lx\n", InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE));
60 SetLastError(ERROR_INVALID_FLAGS);
61 goto cleanup;
62 }*/
63
64 /* Enumerate all devices of the system */
65 DevInstData.hDevInfo = SetupDiGetClassDevsW(NULL, NULL, hwndParent, DIGCF_ALLCLASSES | DIGCF_PRESENT);
66 if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE)
67 goto cleanup;
68 DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
69 for (i = 0; ; i++)
70 {
71 if (!SetupDiEnumDeviceInfo(DevInstData.hDevInfo, i, &DevInstData.devInfoData))
72 {
73 if (GetLastError() != ERROR_NO_MORE_ITEMS)
74 {
75 TRACE("SetupDiEnumDeviceInfo() failed with error 0x%lx\n", GetLastError());
76 goto cleanup;
77 }
78 /* This error was expected */
79 break;
80 }
81
82 /* Get Hardware ID */
83 HeapFree(GetProcessHeap(), 0, Buffer);
84 Buffer = NULL;
85 BufferSize = 0;
86 while (!SetupDiGetDeviceRegistryPropertyW(
87 DevInstData.hDevInfo,
88 &DevInstData.devInfoData,
89 SPDRP_HARDWAREID,
90 NULL,
91 (PBYTE)Buffer,
92 BufferSize,
93 &BufferSize))
94 {
95 if (GetLastError() == ERROR_FILE_NOT_FOUND)
96 {
97 Buffer = NULL;
98 break;
99 }
100 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
101 {
102 TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%lx\n", GetLastError());
103 goto cleanup;
104 }
105 /* This error was expected */
106 HeapFree(GetProcessHeap(), 0, Buffer);
107 Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
108 if (!Buffer)
109 {
110 TRACE("HeapAlloc() failed\n", GetLastError());
111 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
112 goto cleanup;
113 }
114 }
115 if (Buffer == NULL)
116 continue;
117
118 /* Check if we match the given hardware ID */
119 FoundHardwareId = FALSE;
120 for (CurrentHardwareId = Buffer; *CurrentHardwareId != UNICODE_NULL; CurrentHardwareId += wcslen(CurrentHardwareId) + 1)
121 {
122 if (wcscmp(CurrentHardwareId, HardwareId) == 0)
123 {
124 FoundHardwareId = TRUE;
125 break;
126 }
127 }
128 if (!FoundHardwareId)
129 continue;
130
131 /* We need to try to update the driver of this device */
132
133 /* Get Instance ID */
134 HeapFree(GetProcessHeap(), 0, Buffer);
135 Buffer = NULL;
136 if (SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, NULL, 0, &BufferSize))
137 {
138 /* Error, as the output buffer should be too small */
139 SetLastError(ERROR_GEN_FAILURE);
140 goto cleanup;
141 }
142 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
143 {
144 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
145 goto cleanup;
146 }
147 else if ((Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize)) == NULL)
148 {
149 TRACE("HeapAlloc() failed\n", GetLastError());
150 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
151 goto cleanup;
152 }
153 else if (!SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, Buffer, BufferSize, NULL))
154 {
155 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
156 goto cleanup;
157 }
158 TRACE("Trying to update the driver of %S\n", Buffer);
159
160 /* Search driver in the specified .inf file */
161 if (!SearchDriver(&DevInstData, NULL, FullInfPath))
162 {
163 TRACE("SearchDriver() failed with error 0x%lx\n", GetLastError());
164 continue;
165 }
166
167 /* FIXME: HACK! We shouldn't check of ERROR_PRIVILEGE_NOT_HELD */
168 //if (!InstallCurrentDriver(&DevInstData))
169 if (!InstallCurrentDriver(&DevInstData) && GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
170 {
171 TRACE("InstallCurrentDriver() failed with error 0x%lx\n", GetLastError());
172 continue;
173 }
174
175 FoundAtLeastOneDevice = TRUE;
176 }
177
178 if (FoundAtLeastOneDevice)
179 {
180 SetLastError(NO_ERROR);
181 ret = TRUE;
182 }
183 else
184 {
185 TRACE("No device found with HardwareID %S\n", HardwareId);
186 SetLastError(ERROR_NO_SUCH_DEVINST);
187 }
188
189 cleanup:
190 if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE)
191 SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo);
192 HeapFree(GetProcessHeap(), 0, Buffer);
193 return ret;
194 }
195
196 /*
197 * @implemented
198 */
199 BOOL WINAPI
200 UpdateDriverForPlugAndPlayDevicesA(
201 IN HWND hwndParent,
202 IN LPCSTR HardwareId,
203 IN LPCSTR FullInfPath,
204 IN DWORD InstallFlags,
205 OUT PBOOL bRebootRequired OPTIONAL)
206 {
207 BOOL Result;
208 LPWSTR HardwareIdW = NULL;
209 LPWSTR FullInfPathW = NULL;
210
211 int len = MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, NULL, 0);
212 HardwareIdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
213 if (!HardwareIdW)
214 {
215 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
216 return FALSE;
217 }
218 MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, HardwareIdW, len);
219
220 len = MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, NULL, 0);
221 FullInfPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
222 if (!FullInfPathW)
223 {
224 HeapFree(GetProcessHeap(), 0, HardwareIdW);
225 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
226 return FALSE;
227 }
228 MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, FullInfPathW, len);
229
230 Result = UpdateDriverForPlugAndPlayDevicesW(
231 hwndParent,
232 HardwareIdW,
233 FullInfPathW,
234 InstallFlags,
235 bRebootRequired);
236
237 HeapFree(GetProcessHeap(), 0, HardwareIdW);
238 HeapFree(GetProcessHeap(), 0, FullInfPathW);
239
240 return Result;
241 }
242
243 /* Directory and InfFile MUST NOT be specified simultaneously */
244 BOOL
245 SearchDriver(
246 IN PDEVINSTDATA DevInstData,
247 IN LPCTSTR Directory OPTIONAL,
248 IN LPCTSTR InfFile OPTIONAL)
249 {
250 SP_DEVINSTALL_PARAMS DevInstallParams = {0,};
251 BOOL ret;
252
253 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
254 if (!SetupDiGetDeviceInstallParams(DevInstData->hDevInfo, &DevInstData->devInfoData, &DevInstallParams))
255 {
256 TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
257 return FALSE;
258 }
259 DevInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
260
261 if (InfFile)
262 {
263 DevInstallParams.Flags |= DI_ENUMSINGLEINF;
264 _tcsncpy(DevInstallParams.DriverPath, InfFile, MAX_PATH);
265 }
266 else if (Directory)
267 {
268 DevInstallParams.Flags &= ~DI_ENUMSINGLEINF;
269 _tcsncpy(DevInstallParams.DriverPath, Directory, MAX_PATH);
270 }
271 else
272 *DevInstallParams.DriverPath = _T('\0');
273
274 ret = SetupDiSetDeviceInstallParams(
275 DevInstData->hDevInfo,
276 &DevInstData->devInfoData,
277 &DevInstallParams);
278 if (!ret)
279 {
280 TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
281 return FALSE;
282 }
283
284 ret = SetupDiBuildDriverInfoList(
285 DevInstData->hDevInfo,
286 &DevInstData->devInfoData,
287 SPDIT_COMPATDRIVER);
288 if (!ret)
289 {
290 TRACE("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
291 return FALSE;
292 }
293
294 DevInstData->drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
295 ret = SetupDiEnumDriverInfo(
296 DevInstData->hDevInfo,
297 &DevInstData->devInfoData,
298 SPDIT_COMPATDRIVER,
299 0,
300 &DevInstData->drvInfoData);
301 if (!ret)
302 {
303 if (GetLastError() == ERROR_NO_MORE_ITEMS)
304 return FALSE;
305 TRACE("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
306 return FALSE;
307 }
308
309 return TRUE;
310 }
311
312
313 static BOOL
314 IsDots(IN LPCTSTR str)
315 {
316 if(_tcscmp(str, _T(".")) && _tcscmp(str, _T(".."))) return FALSE;
317 return TRUE;
318 }
319
320 static LPTSTR
321 GetFileExt(IN LPTSTR FileName)
322 {
323 if (FileName == 0)
324 return _T("");
325
326 int i = _tcsclen(FileName);
327 while ((i >= 0) && (FileName[i] != _T('.')))
328 i--;
329
330 FileName = _tcslwr(FileName);
331
332 if (i >= 0)
333 return &FileName[i];
334 else
335 return _T("");
336 }
337
338 BOOL
339 SearchDriverRecursive(
340 IN PDEVINSTDATA DevInstData,
341 IN LPCTSTR Path)
342 {
343 WIN32_FIND_DATA wfd;
344 TCHAR DirPath[MAX_PATH];
345 TCHAR FileName[MAX_PATH];
346 TCHAR FullPath[MAX_PATH];
347 TCHAR LastDirPath[MAX_PATH] = _T("");
348 TCHAR PathWithPattern[MAX_PATH];
349 BOOL ok = TRUE;
350 BOOL retval = FALSE;
351 HANDLE hFindFile = INVALID_HANDLE_VALUE;
352
353 _tcscpy(DirPath, Path);
354
355 if (DirPath[_tcsclen(DirPath) - 1] != '\\')
356 _tcscat(DirPath, _T("\\"));
357
358 _tcscpy(PathWithPattern, DirPath);
359 _tcscat(PathWithPattern, _T("\\*"));
360
361 for (hFindFile = FindFirstFile(PathWithPattern, &wfd);
362 ok && hFindFile != INVALID_HANDLE_VALUE;
363 ok = FindNextFile(hFindFile, &wfd))
364 {
365
366 _tcscpy(FileName, wfd.cFileName);
367 if (IsDots(FileName))
368 continue;
369
370 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
371 {
372 /* Recursive search */
373 _tcscpy(FullPath, DirPath);
374 _tcscat(FullPath, FileName);
375 if (SearchDriverRecursive(DevInstData, FullPath))
376 break;
377 }
378 else
379 {
380 LPCTSTR pszExtension = GetFileExt(FileName);
381
382 if ((_tcscmp(pszExtension, _T(".inf")) == 0) && (_tcscmp(LastDirPath, DirPath) != 0))
383 {
384 _tcscpy(LastDirPath, DirPath);
385
386 if (_tcsclen(DirPath) > MAX_PATH)
387 /* Path is too long to be searched */
388 continue;
389
390 if (SearchDriver(DevInstData, DirPath, NULL))
391 {
392 retval = TRUE;
393 goto cleanup;
394 }
395
396 }
397 }
398 }
399
400 cleanup:
401 if (hFindFile != INVALID_HANDLE_VALUE)
402 FindClose(hFindFile);
403 return retval;
404 }
405
406 BOOL
407 InstallCurrentDriver(
408 IN PDEVINSTDATA DevInstData)
409 {
410 BOOL ret;
411
412 TRACE("Installing driver %S: %S\n", DevInstData->drvInfoData.MfgName, DevInstData->drvInfoData.Description);
413
414 ret = SetupDiCallClassInstaller(
415 DIF_SELECTBESTCOMPATDRV,
416 DevInstData->hDevInfo,
417 &DevInstData->devInfoData);
418 if (!ret)
419 {
420 TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%lx\n", GetLastError());
421 return FALSE;
422 }
423
424 ret = SetupDiCallClassInstaller(
425 DIF_ALLOW_INSTALL,
426 DevInstData->hDevInfo,
427 &DevInstData->devInfoData);
428 if (!ret)
429 {
430 TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%lx\n", GetLastError());
431 return FALSE;
432 }
433
434 ret = SetupDiCallClassInstaller(
435 DIF_NEWDEVICEWIZARD_PREANALYZE,
436 DevInstData->hDevInfo,
437 &DevInstData->devInfoData);
438 if (!ret)
439 {
440 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%lx\n", GetLastError());
441 return FALSE;
442 }
443
444 ret = SetupDiCallClassInstaller(
445 DIF_NEWDEVICEWIZARD_POSTANALYZE,
446 DevInstData->hDevInfo,
447 &DevInstData->devInfoData);
448 if (!ret)
449 {
450 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%lx\n", GetLastError());
451 return FALSE;
452 }
453
454 ret = SetupDiCallClassInstaller(
455 DIF_INSTALLDEVICEFILES,
456 DevInstData->hDevInfo,
457 &DevInstData->devInfoData);
458 if (!ret)
459 {
460 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%lx\n", GetLastError());
461 return FALSE;
462 }
463
464 ret = SetupDiCallClassInstaller(
465 DIF_REGISTER_COINSTALLERS,
466 DevInstData->hDevInfo,
467 &DevInstData->devInfoData);
468 if (!ret)
469 {
470 TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%lx\n", GetLastError());
471 return FALSE;
472 }
473
474 ret = SetupDiCallClassInstaller(
475 DIF_INSTALLINTERFACES,
476 DevInstData->hDevInfo,
477 &DevInstData->devInfoData);
478 if (!ret)
479 {
480 TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%lx\n", GetLastError());
481 return FALSE;
482 }
483
484 ret = SetupDiCallClassInstaller(
485 DIF_INSTALLDEVICE,
486 DevInstData->hDevInfo,
487 &DevInstData->devInfoData);
488 if (!ret)
489 {
490 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%lx\n", GetLastError());
491 return FALSE;
492 }
493
494 ret = SetupDiCallClassInstaller(
495 DIF_NEWDEVICEWIZARD_FINISHINSTALL,
496 DevInstData->hDevInfo,
497 &DevInstData->devInfoData);
498 if (!ret)
499 {
500 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%lx\n", GetLastError());
501 return FALSE;
502 }
503
504 ret = SetupDiCallClassInstaller(
505 DIF_DESTROYPRIVATEDATA,
506 DevInstData->hDevInfo,
507 &DevInstData->devInfoData);
508 if (!ret)
509 {
510 TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%lx\n", GetLastError());
511 return FALSE;
512 }
513
514 return TRUE;
515 }
516
517 /*
518 * @implemented
519 */
520 BOOL WINAPI
521 DevInstallW(
522 IN HWND hWndParent,
523 IN HINSTANCE hInstance,
524 IN LPCWSTR InstanceId,
525 IN INT Show)
526 {
527 PDEVINSTDATA DevInstData = NULL;
528 BOOL ret;
529 DWORD config_flags;
530 BOOL retval = FALSE;
531
532 if (!IsUserAdmin())
533 {
534 /* XP kills the process... */
535 ExitProcess(ERROR_ACCESS_DENIED);
536 }
537
538 DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
539 if (!DevInstData)
540 {
541 TRACE("HeapAlloc() failed\n");
542 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
543 goto cleanup;
544 }
545
546 /* Clear devinst data */
547 ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
548 DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
549
550 /* Fill devinst data */
551 DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
552 if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
553 {
554 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%lx\n", GetLastError());
555 goto cleanup;
556 }
557
558 DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
559 ret = SetupDiOpenDeviceInfoW(
560 DevInstData->hDevInfo,
561 InstanceId,
562 NULL,
563 0, /* Open flags */
564 &DevInstData->devInfoData);
565 if (!ret)
566 {
567 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId);
568 DevInstData->devInfoData.cbSize = 0;
569 goto cleanup;
570 }
571
572 SetLastError(ERROR_GEN_FAILURE);
573 ret = SetupDiGetDeviceRegistryProperty(
574 DevInstData->hDevInfo,
575 &DevInstData->devInfoData,
576 SPDRP_DEVICEDESC,
577 &DevInstData->regDataType,
578 NULL, 0,
579 &DevInstData->requiredSize);
580
581 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
582 {
583 DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
584 if (!DevInstData->buffer)
585 {
586 TRACE("HeapAlloc() failed\n");
587 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
588 }
589 else
590 {
591 ret = SetupDiGetDeviceRegistryProperty(
592 DevInstData->hDevInfo,
593 &DevInstData->devInfoData,
594 SPDRP_DEVICEDESC,
595 &DevInstData->regDataType,
596 DevInstData->buffer, DevInstData->requiredSize,
597 &DevInstData->requiredSize);
598 }
599 }
600 if (!ret)
601 {
602 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId);
603 goto cleanup;
604 }
605
606 if (SetupDiGetDeviceRegistryProperty(
607 DevInstData->hDevInfo,
608 &DevInstData->devInfoData,
609 SPDRP_CONFIGFLAGS,
610 NULL,
611 (BYTE *)&config_flags,
612 sizeof(config_flags),
613 NULL))
614 {
615 if (config_flags & CONFIGFLAG_FAILEDINSTALL)
616 {
617 /* The device is disabled */
618 retval = TRUE;
619 goto cleanup;
620 }
621 }
622
623 TRACE("Installing %S (%S)\n", DevInstData->buffer, InstanceId);
624
625 /* Search driver in default location */
626 if (SearchDriver(DevInstData, NULL, NULL))
627 {
628 /* Driver found ; install it */
629 retval = InstallCurrentDriver(DevInstData);
630 goto cleanup;
631 }
632 else if (Show == SW_HIDE)
633 {
634 /* We can't show the wizard. Fail the install */
635 goto cleanup;
636 }
637
638 /* Prepare the wizard, and display it */
639 retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
640
641 cleanup:
642 if (DevInstData)
643 {
644 if (DevInstData->devInfoData.cbSize != 0)
645 {
646 if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
647 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
648 }
649 if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
650 {
651 if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
652 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
653 }
654 HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
655 HeapFree(GetProcessHeap(), 0, DevInstData);
656 }
657
658 return retval;
659 }
660
661 /*
662 * @unimplemented
663 */
664 BOOL WINAPI
665 ClientSideInstallW(
666 IN HWND hWndOwner,
667 IN DWORD dwUnknownFlags,
668 IN LPWSTR lpNamedPipeName)
669 {
670 /* NOTE: pNamedPipeName is in the format:
671 * "\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
672 */
673 FIXME("Stub\n");
674 return FALSE;
675 }
676
677 BOOL WINAPI
678 DllMain(
679 IN HINSTANCE hInstance,
680 IN DWORD dwReason,
681 IN LPVOID lpReserved)
682 {
683 if (dwReason == DLL_PROCESS_ATTACH)
684 {
685 INITCOMMONCONTROLSEX InitControls;
686
687 DisableThreadLibraryCalls(hInstance);
688
689 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
690 InitControls.dwICC = ICC_PROGRESS_CLASS;
691 InitCommonControlsEx(&InitControls);
692 hDllInstance = hInstance;
693 }
694
695 return TRUE;
696 }