2 * New device installer (newdev.dll)
4 * Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
5 * 2005 Christoph von Wittich (Christoph@ActiveVB.de)
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.
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.
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
23 #include "newdev_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(newdev
);
27 /* Global variables */
28 HINSTANCE hDllInstance
;
32 IN PDEVINSTDATA DevInstData
,
33 IN LPCTSTR Directory OPTIONAL
,
34 IN LPCTSTR InfFile OPTIONAL
);
40 UpdateDriverForPlugAndPlayDevicesW(
42 IN LPCWSTR HardwareId
,
43 IN LPCWSTR FullInfPath
,
44 IN DWORD InstallFlags
,
45 OUT PBOOL bRebootRequired OPTIONAL
)
47 DEVINSTDATA DevInstData
;
51 LPCWSTR CurrentHardwareId
; /* Pointer into Buffer */
52 BOOL FoundHardwareId
, FoundAtLeastOneDevice
= FALSE
;
55 DevInstData
.hDevInfo
= INVALID_HANDLE_VALUE
;
57 TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %S %S 0x%lx %p)\n",
58 hwndParent
, HardwareId
, FullInfPath
, InstallFlags
, bRebootRequired
);
60 /* FIXME: InstallFlags bRebootRequired ignored! */
63 if (InstallFlags
& ~(INSTALLFLAG_FORCE
| INSTALLFLAG_READONLY
| INSTALLFLAG_NONINTERACTIVE
))
65 DPRINT("Unknown flags: 0x%08lx\n", InstallFlags
& ~(INSTALLFLAG_FORCE
| INSTALLFLAG_READONLY
| INSTALLFLAG_NONINTERACTIVE
));
66 SetLastError(ERROR_INVALID_FLAGS
);
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
)
74 DevInstData
.devInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
77 if (!SetupDiEnumDeviceInfo(DevInstData
.hDevInfo
, i
, &DevInstData
.devInfoData
))
79 if (GetLastError() != ERROR_NO_MORE_ITEMS
)
81 TRACE("SetupDiEnumDeviceInfo() failed with error 0x%lx\n", GetLastError());
84 /* This error was expected */
89 HeapFree(GetProcessHeap(), 0, Buffer
);
92 while (!SetupDiGetDeviceRegistryPropertyW(
94 &DevInstData
.devInfoData
,
101 if (GetLastError() == ERROR_FILE_NOT_FOUND
)
106 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
108 TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%lx\n", GetLastError());
111 /* This error was expected */
112 HeapFree(GetProcessHeap(), 0, Buffer
);
113 Buffer
= HeapAlloc(GetProcessHeap(), 0, BufferSize
);
116 TRACE("HeapAlloc() failed\n", GetLastError());
117 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
124 /* Check if we match the given hardware ID */
125 FoundHardwareId
= FALSE
;
126 for (CurrentHardwareId
= Buffer
; *CurrentHardwareId
!= UNICODE_NULL
; CurrentHardwareId
+= wcslen(CurrentHardwareId
) + 1)
128 if (wcscmp(CurrentHardwareId
, HardwareId
) == 0)
130 FoundHardwareId
= TRUE
;
134 if (!FoundHardwareId
)
137 /* We need to try to update the driver of this device */
139 /* Get Instance ID */
140 HeapFree(GetProcessHeap(), 0, Buffer
);
142 if (SetupDiGetDeviceInstanceIdW(DevInstData
.hDevInfo
, &DevInstData
.devInfoData
, NULL
, 0, &BufferSize
))
144 /* Error, as the output buffer should be too small */
145 SetLastError(ERROR_GEN_FAILURE
);
148 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
150 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
153 else if ((Buffer
= HeapAlloc(GetProcessHeap(), 0, BufferSize
)) == NULL
)
155 TRACE("HeapAlloc() failed\n", GetLastError());
156 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
159 else if (!SetupDiGetDeviceInstanceIdW(DevInstData
.hDevInfo
, &DevInstData
.devInfoData
, Buffer
, BufferSize
, NULL
))
161 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
164 TRACE("Trying to update the driver of %S\n", Buffer
);
166 /* Search driver in the specified .inf file */
167 if (!SearchDriver(&DevInstData
, NULL
, FullInfPath
))
169 TRACE("SearchDriver() failed with error 0x%lx\n", GetLastError());
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
)
177 TRACE("InstallCurrentDriver() failed with error 0x%lx\n", GetLastError());
181 FoundAtLeastOneDevice
= TRUE
;
184 if (FoundAtLeastOneDevice
)
186 SetLastError(NO_ERROR
);
191 TRACE("No device found with HardwareID %S\n", HardwareId
);
192 SetLastError(ERROR_NO_SUCH_DEVINST
);
196 if (DevInstData
.hDevInfo
!= INVALID_HANDLE_VALUE
)
197 SetupDiDestroyDeviceInfoList(DevInstData
.hDevInfo
);
198 HeapFree(GetProcessHeap(), 0, Buffer
);
206 UpdateDriverForPlugAndPlayDevicesA(
208 IN LPCSTR HardwareId
,
209 IN LPCSTR FullInfPath
,
210 IN DWORD InstallFlags
,
211 OUT PBOOL bRebootRequired OPTIONAL
)
214 LPWSTR HardwareIdW
= NULL
;
215 LPWSTR FullInfPathW
= NULL
;
217 int len
= MultiByteToWideChar(CP_ACP
, 0, HardwareId
, -1, NULL
, 0);
218 HardwareIdW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
221 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
224 MultiByteToWideChar(CP_ACP
, 0, HardwareId
, -1, HardwareIdW
, len
);
226 len
= MultiByteToWideChar(CP_ACP
, 0, FullInfPath
, -1, NULL
, 0);
227 FullInfPathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
230 HeapFree(GetProcessHeap(), 0, HardwareIdW
);
231 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
234 MultiByteToWideChar(CP_ACP
, 0, FullInfPath
, -1, FullInfPathW
, len
);
236 Result
= UpdateDriverForPlugAndPlayDevicesW(
243 HeapFree(GetProcessHeap(), 0, HardwareIdW
);
244 HeapFree(GetProcessHeap(), 0, FullInfPathW
);
249 /* Directory and InfFile MUST NOT be specified simultaneously */
252 IN PDEVINSTDATA DevInstData
,
253 IN LPCTSTR Directory OPTIONAL
,
254 IN LPCTSTR InfFile OPTIONAL
)
256 SP_DEVINSTALL_PARAMS DevInstallParams
= {0,};
259 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
260 if (!SetupDiGetDeviceInstallParams(DevInstData
->hDevInfo
, &DevInstData
->devInfoData
, &DevInstallParams
))
262 TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
265 DevInstallParams
.FlagsEx
|= DI_FLAGSEX_ALLOWEXCLUDEDDRVS
;
269 DevInstallParams
.Flags
|= DI_ENUMSINGLEINF
;
270 _tcsncpy(DevInstallParams
.DriverPath
, InfFile
, MAX_PATH
);
274 DevInstallParams
.Flags
&= ~DI_ENUMSINGLEINF
;
275 _tcsncpy(DevInstallParams
.DriverPath
, Directory
, MAX_PATH
);
279 DevInstallParams
.Flags
&= ~DI_ENUMSINGLEINF
;
280 *DevInstallParams
.DriverPath
= _T('\0');
283 ret
= SetupDiSetDeviceInstallParams(
284 DevInstData
->hDevInfo
,
285 &DevInstData
->devInfoData
,
289 TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
293 ret
= SetupDiBuildDriverInfoList(
294 DevInstData
->hDevInfo
,
295 &DevInstData
->devInfoData
,
299 TRACE("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
303 DevInstData
->drvInfoData
.cbSize
= sizeof(SP_DRVINFO_DATA
);
304 ret
= SetupDiEnumDriverInfo(
305 DevInstData
->hDevInfo
,
306 &DevInstData
->devInfoData
,
309 &DevInstData
->drvInfoData
);
312 if (GetLastError() == ERROR_NO_MORE_ITEMS
)
314 TRACE("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
322 IsDots(IN LPCTSTR str
)
324 if(_tcscmp(str
, _T(".")) && _tcscmp(str
, _T(".."))) return FALSE
;
329 GetFileExt(IN LPTSTR FileName
)
334 int i
= _tcsclen(FileName
);
335 while ((i
>= 0) && (FileName
[i
] != _T('.')))
338 FileName
= _tcslwr(FileName
);
347 SearchDriverRecursive(
348 IN PDEVINSTDATA DevInstData
,
352 TCHAR DirPath
[MAX_PATH
];
353 TCHAR FileName
[MAX_PATH
];
354 TCHAR FullPath
[MAX_PATH
];
355 TCHAR LastDirPath
[MAX_PATH
] = _T("");
356 TCHAR PathWithPattern
[MAX_PATH
];
359 HANDLE hFindFile
= INVALID_HANDLE_VALUE
;
361 _tcscpy(DirPath
, Path
);
363 if (DirPath
[_tcsclen(DirPath
) - 1] != '\\')
364 _tcscat(DirPath
, _T("\\"));
366 _tcscpy(PathWithPattern
, DirPath
);
367 _tcscat(PathWithPattern
, _T("\\*"));
369 for (hFindFile
= FindFirstFile(PathWithPattern
, &wfd
);
370 ok
&& hFindFile
!= INVALID_HANDLE_VALUE
;
371 ok
= FindNextFile(hFindFile
, &wfd
))
374 _tcscpy(FileName
, wfd
.cFileName
);
375 if (IsDots(FileName
))
378 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
380 /* Recursive search */
381 _tcscpy(FullPath
, DirPath
);
382 _tcscat(FullPath
, FileName
);
383 if (SearchDriverRecursive(DevInstData
, FullPath
))
386 /* We continue the search for a better driver */
391 LPCTSTR pszExtension
= GetFileExt(FileName
);
393 if ((_tcscmp(pszExtension
, _T(".inf")) == 0) && (_tcscmp(LastDirPath
, DirPath
) != 0))
395 _tcscpy(LastDirPath
, DirPath
);
397 if (_tcsclen(DirPath
) > MAX_PATH
)
398 /* Path is too long to be searched */
401 if (SearchDriver(DevInstData
, DirPath
, NULL
))
404 /* We continue the search for a better driver */
411 if (hFindFile
!= INVALID_HANDLE_VALUE
)
412 FindClose(hFindFile
);
417 ScanFoldersForDriver(
418 IN PDEVINSTDATA DevInstData
)
422 /* Search in default location */
423 result
= SearchDriver(DevInstData
, NULL
, NULL
);
425 if (DevInstData
->CustomSearchPath
)
427 /* Search only in specified paths */
428 /* We need to check all specified directories to be
429 * sure to find the best driver for the device.
432 for (Path
= DevInstData
->CustomSearchPath
; *Path
!= '\0'; Path
+= _tcslen(Path
) + 1)
434 TRACE("Search driver in %S\n", Path
);
435 if (_tcslen(Path
) == 2 && Path
[1] == ':')
437 if (SearchDriverRecursive(DevInstData
, Path
))
442 if (SearchDriver(DevInstData
, Path
, NULL
))
452 PrepareFoldersToScan(
453 IN PDEVINSTDATA DevInstData
,
454 IN BOOL IncludeRemovableDevices
,
455 IN BOOL IncludeCustomPath
,
456 IN HWND hwndCombo OPTIONAL
)
458 TCHAR drive
[] = {'?',':',0};
462 DWORD CustomTextLength
= 0;
463 DWORD LengthNeeded
= 0;
466 TRACE("Include removable devices: %s\n", IncludeRemovableDevices
? "yes" : "no");
467 TRACE("Include custom path : %s\n", IncludeCustomPath
? "yes" : "no");
469 /* Calculate length needed to store the search paths */
470 if (IncludeRemovableDevices
)
472 dwDrives
= GetLogicalDrives();
473 for (drive
[0] = 'A', i
= 1; drive
[0] <= 'Z'; drive
[0]++, i
<<= 1)
477 nType
= GetDriveType(drive
);
478 if (nType
== DRIVE_REMOVABLE
|| nType
== DRIVE_CDROM
)
485 if (IncludeCustomPath
)
487 CustomTextLength
= 1 + ComboBox_GetTextLength(hwndCombo
);
488 LengthNeeded
+= CustomTextLength
;
491 /* Allocate space for search paths */
492 HeapFree(GetProcessHeap(), 0, DevInstData
->CustomSearchPath
);
493 DevInstData
->CustomSearchPath
= Buffer
= HeapAlloc(
496 (LengthNeeded
+ 1) * sizeof(TCHAR
));
499 TRACE("HeapAlloc() failed\n");
500 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
504 /* Fill search paths */
505 if (IncludeRemovableDevices
)
507 for (drive
[0] = 'A', i
= 1; drive
[0] <= 'Z'; drive
[0]++, i
<<= 1)
511 nType
= GetDriveType(drive
);
512 if (nType
== DRIVE_REMOVABLE
|| nType
== DRIVE_CDROM
)
514 Buffer
+= 1 + _stprintf(Buffer
, drive
);
519 if (IncludeCustomPath
)
521 Buffer
+= 1 + ComboBox_GetText(hwndCombo
, Buffer
, CustomTextLength
);
529 InstallCurrentDriver(
530 IN PDEVINSTDATA DevInstData
)
534 TRACE("Installing driver %S: %S\n", DevInstData
->drvInfoData
.MfgName
, DevInstData
->drvInfoData
.Description
);
536 ret
= SetupDiCallClassInstaller(
537 DIF_SELECTBESTCOMPATDRV
,
538 DevInstData
->hDevInfo
,
539 &DevInstData
->devInfoData
);
542 TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%lx\n", GetLastError());
546 ret
= SetupDiCallClassInstaller(
548 DevInstData
->hDevInfo
,
549 &DevInstData
->devInfoData
);
552 TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%lx\n", GetLastError());
556 ret
= SetupDiCallClassInstaller(
557 DIF_NEWDEVICEWIZARD_PREANALYZE
,
558 DevInstData
->hDevInfo
,
559 &DevInstData
->devInfoData
);
562 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%lx\n", GetLastError());
566 ret
= SetupDiCallClassInstaller(
567 DIF_NEWDEVICEWIZARD_POSTANALYZE
,
568 DevInstData
->hDevInfo
,
569 &DevInstData
->devInfoData
);
572 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%lx\n", GetLastError());
576 ret
= SetupDiCallClassInstaller(
577 DIF_INSTALLDEVICEFILES
,
578 DevInstData
->hDevInfo
,
579 &DevInstData
->devInfoData
);
582 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%lx\n", GetLastError());
586 ret
= SetupDiCallClassInstaller(
587 DIF_REGISTER_COINSTALLERS
,
588 DevInstData
->hDevInfo
,
589 &DevInstData
->devInfoData
);
592 TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%lx\n", GetLastError());
596 ret
= SetupDiCallClassInstaller(
597 DIF_INSTALLINTERFACES
,
598 DevInstData
->hDevInfo
,
599 &DevInstData
->devInfoData
);
602 TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%lx\n", GetLastError());
606 ret
= SetupDiCallClassInstaller(
608 DevInstData
->hDevInfo
,
609 &DevInstData
->devInfoData
);
612 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%lx\n", GetLastError());
616 ret
= SetupDiCallClassInstaller(
617 DIF_NEWDEVICEWIZARD_FINISHINSTALL
,
618 DevInstData
->hDevInfo
,
619 &DevInstData
->devInfoData
);
622 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%lx\n", GetLastError());
626 ret
= SetupDiCallClassInstaller(
627 DIF_DESTROYPRIVATEDATA
,
628 DevInstData
->hDevInfo
,
629 &DevInstData
->devInfoData
);
632 TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%lx\n", GetLastError());
645 IN HINSTANCE hInstance
,
646 IN LPCWSTR InstanceId
,
649 PDEVINSTDATA DevInstData
= NULL
;
656 /* XP kills the process... */
657 ExitProcess(ERROR_ACCESS_DENIED
);
660 DevInstData
= HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA
));
663 TRACE("HeapAlloc() failed\n");
664 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
668 /* Clear devinst data */
669 ZeroMemory(DevInstData
, sizeof(DEVINSTDATA
));
670 DevInstData
->devInfoData
.cbSize
= 0; /* Tell if the devInfoData is valid */
672 /* Fill devinst data */
673 DevInstData
->hDevInfo
= SetupDiCreateDeviceInfoListExW(NULL
, NULL
, NULL
, NULL
);
674 if (DevInstData
->hDevInfo
== INVALID_HANDLE_VALUE
)
676 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%lx\n", GetLastError());
680 DevInstData
->devInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
681 ret
= SetupDiOpenDeviceInfoW(
682 DevInstData
->hDevInfo
,
686 &DevInstData
->devInfoData
);
689 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId
);
690 DevInstData
->devInfoData
.cbSize
= 0;
694 SetLastError(ERROR_GEN_FAILURE
);
695 ret
= SetupDiGetDeviceRegistryProperty(
696 DevInstData
->hDevInfo
,
697 &DevInstData
->devInfoData
,
699 &DevInstData
->regDataType
,
701 &DevInstData
->requiredSize
);
703 if (!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
&& DevInstData
->regDataType
== REG_SZ
)
705 DevInstData
->buffer
= HeapAlloc(GetProcessHeap(), 0, DevInstData
->requiredSize
);
706 if (!DevInstData
->buffer
)
708 TRACE("HeapAlloc() failed\n");
709 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
713 ret
= SetupDiGetDeviceRegistryProperty(
714 DevInstData
->hDevInfo
,
715 &DevInstData
->devInfoData
,
717 &DevInstData
->regDataType
,
718 DevInstData
->buffer
, DevInstData
->requiredSize
,
719 &DevInstData
->requiredSize
);
724 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId
);
728 if (SetupDiGetDeviceRegistryProperty(
729 DevInstData
->hDevInfo
,
730 &DevInstData
->devInfoData
,
733 (BYTE
*)&config_flags
,
734 sizeof(config_flags
),
737 if (config_flags
& CONFIGFLAG_FAILEDINSTALL
)
739 /* The device is disabled */
745 TRACE("Installing %S (%S)\n", DevInstData
->buffer
, InstanceId
);
747 /* Search driver in default location and removable devices */
748 if (!PrepareFoldersToScan(DevInstData
, TRUE
, FALSE
, NULL
))
750 TRACE("PrepareFoldersToScan() failed with error 0x%lx\n", GetLastError());
753 if (ScanFoldersForDriver(DevInstData
))
755 /* Driver found ; install it */
756 retval
= InstallCurrentDriver(DevInstData
);
759 else if (Show
== SW_HIDE
)
761 /* We can't show the wizard. Fail the install */
765 /* Prepare the wizard, and display it */
766 retval
= DisplayWizard(DevInstData
, hWndParent
, IDD_WELCOMEPAGE
);
771 if (DevInstData
->devInfoData
.cbSize
!= 0)
773 if (!SetupDiDestroyDriverInfoList(DevInstData
->hDevInfo
, &DevInstData
->devInfoData
, SPDIT_COMPATDRIVER
))
774 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
776 if (DevInstData
->hDevInfo
!= INVALID_HANDLE_VALUE
)
778 if (!SetupDiDestroyDeviceInfoList(DevInstData
->hDevInfo
))
779 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
781 HeapFree(GetProcessHeap(), 0, DevInstData
->buffer
);
782 HeapFree(GetProcessHeap(), 0, DevInstData
);
794 IN DWORD dwUnknownFlags
,
795 IN LPWSTR lpNamedPipeName
)
797 /* NOTE: pNamedPipeName is in the format:
798 * "\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
806 IN HINSTANCE hInstance
,
808 IN LPVOID lpReserved
)
810 if (dwReason
== DLL_PROCESS_ATTACH
)
812 INITCOMMONCONTROLSEX InitControls
;
814 DisableThreadLibraryCalls(hInstance
);
816 InitControls
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
817 InitControls
.dwICC
= ICC_PROGRESS_CLASS
;
818 InitCommonControlsEx(&InitControls
);
819 hDllInstance
= hInstance
;