From: Hervé Poussineau Date: Thu, 25 May 2006 23:34:41 +0000 (+0000) Subject: Of course, I forgot to commit the new file in revision 22049... X-Git-Tag: ReactOS-0.3.0~45^4~1 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=a10d9d8b2b984b47d16d8e855f1b89ee209a1f17 Of course, I forgot to commit the new file in revision 22049... svn path=/trunk/; revision=22050 --- diff --git a/reactos/dll/win32/newdev/wizard.c b/reactos/dll/win32/newdev/wizard.c new file mode 100644 index 00000000000..fc617e14e69 --- /dev/null +++ b/reactos/dll/win32/newdev/wizard.c @@ -0,0 +1,838 @@ +/* + * New device installer (newdev.dll) + * + * Copyright 2006 Hervé Poussineau (hpoussin@reactos.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define YDEBUG +#include "newdev.h" + +WINE_DEFAULT_DEBUG_CHANNEL(newdev); + +HANDLE hThread; + +static VOID +CenterWindow( + IN HWND hWnd) +{ + HWND hWndParent; + RECT rcParent; + RECT rcWindow; + + hWndParent = GetParent(hWnd); + if (hWndParent == NULL) + hWndParent = GetDesktopWindow(); + + GetWindowRect(hWndParent, &rcParent); + GetWindowRect(hWnd, &rcWindow); + + SetWindowPos( + hWnd, + HWND_TOP, + ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2, + ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2, + 0, + 0, + SWP_NOSIZE); +} + +static BOOL +CanDisableDevice( + IN DEVINST DevInst, + IN HMACHINE hMachine, + OUT BOOL *CanDisable) +{ +#if 0 + /* hpoussin, Dec 2005. I've disabled this code because + * ntoskrnl never sets the DN_DISABLEABLE flag. + */ + CONFIGRET cr; + ULONG Status, ProblemNumber; + BOOL Ret = FALSE; + + cr = CM_Get_DevNode_Status_Ex( + &Status, + &ProblemNumber, + DevInst, + 0, + hMachine); + if (cr == CR_SUCCESS) + { + *CanDisable = ((Status & DN_DISABLEABLE) != 0); + Ret = TRUE; + } + + return Ret; +#else + *CanDisable = TRUE; + return TRUE; +#endif +} + +static BOOL +IsDeviceStarted( + IN DEVINST DevInst, + IN HMACHINE hMachine, + OUT BOOL *IsEnabled) +{ + CONFIGRET cr; + ULONG Status, ProblemNumber; + BOOL Ret = FALSE; + + cr = CM_Get_DevNode_Status_Ex( + &Status, + &ProblemNumber, + DevInst, + 0, + hMachine); + if (cr == CR_SUCCESS) + { + *IsEnabled = ((Status & DN_STARTED) != 0); + Ret = TRUE; + } + + return Ret; +} + +static BOOL +StartDevice( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DevInfoData OPTIONAL, + IN BOOL bEnable, + IN DWORD HardwareProfile OPTIONAL, + OUT BOOL *bNeedReboot OPTIONAL) +{ + SP_PROPCHANGE_PARAMS pcp; + SP_DEVINSTALL_PARAMS dp; + DWORD LastErr; + BOOL Ret = FALSE; + + pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + pcp.HwProfile = HardwareProfile; + + if (bEnable) + { + /* try to enable the device on the global profile */ + pcp.StateChange = DICS_ENABLE; + pcp.Scope = DICS_FLAG_GLOBAL; + + /* ignore errors */ + LastErr = GetLastError(); + if (SetupDiSetClassInstallParams( + DeviceInfoSet, + DevInfoData, + &pcp.ClassInstallHeader, + sizeof(SP_PROPCHANGE_PARAMS))) + { + SetupDiCallClassInstaller( + DIF_PROPERTYCHANGE, + DeviceInfoSet, + DevInfoData); + } + SetLastError(LastErr); + } + + /* try config-specific */ + pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE); + pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; + + if (SetupDiSetClassInstallParams( + DeviceInfoSet, + DevInfoData, + &pcp.ClassInstallHeader, + sizeof(SP_PROPCHANGE_PARAMS)) && + SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, + DeviceInfoSet, + DevInfoData)) + { + dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + if (SetupDiGetDeviceInstallParams( + DeviceInfoSet, + DevInfoData, + &dp)) + { + if (bNeedReboot != NULL) + { + *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0); + } + + Ret = TRUE; + } + } + return Ret; +} + +static BOOL +PrepareFoldersToScan( + IN PDEVINSTDATA DevInstData, + IN HWND hwndDlg) +{ + FIXME("Include removable devices: %s\n", IsDlgButtonChecked(hwndDlg, IDC_CHECK_MEDIA) ? "yes" : "no"); + FIXME("Include custom path : %s\n", IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH) ? "yes" : "no"); + return TRUE; +} + +static DWORD WINAPI +FindDriverProc( + IN LPVOID lpParam) +{ + TCHAR drive[] = {'?',':',0}; + size_t nType; + DWORD dwDrives; + PDEVINSTDATA DevInstData; + DWORD config_flags; + UINT i = 1; + + DevInstData = (PDEVINSTDATA)lpParam; + DPRINT1("FindDriverProc(%p)\n", DevInstData->CustomSearchPath); + if (DevInstData->CustomSearchPath) + { + LPCTSTR Path; + for (Path = DevInstData->CustomSearchPath; *Path != '\0'; Path += _tcslen(Path) + 1) + DPRINT1("Path %S\n", Path); + } + + dwDrives = GetLogicalDrives(); + for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) + { + if (dwDrives & i) + { + nType = GetDriveType(drive); + if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM) + { + /* search for valid inf file */ + if (SearchDriverRecursive(DevInstData, drive)) + { + InstallCurrentDriver(DevInstData); + PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 1, 0); + return 0; + } + } + } + i <<= 1; + } + + /* update device configuration */ + if (SetupDiGetDeviceRegistryProperty( + DevInstData->hDevInfo, + &DevInstData->devInfoData, + SPDRP_CONFIGFLAGS, + NULL, + (BYTE *)&config_flags, + sizeof(config_flags), + NULL)) + { + config_flags |= CONFIGFLAG_FAILEDINSTALL; + SetupDiSetDeviceRegistryProperty( + DevInstData->hDevInfo, + &DevInstData->devInfoData, + SPDRP_CONFIGFLAGS, + (BYTE *)&config_flags, sizeof(config_flags)); + } + + PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 0, 0); + return 0; +} + +static INT_PTR CALLBACK +WelcomeDlgProc( + IN HWND hwndDlg, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PDEVINSTDATA DevInstData; + + /* Retrieve pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA); + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND hwndControl; + DWORD dwStyle; + + /* Get pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; + SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData); + + hwndControl = GetParent(hwndDlg); + + /* Center the wizard window */ + CenterWindow(hwndControl); + + /* Hide the system menu */ + dwStyle = GetWindowLong(hwndControl, GWL_STYLE); + SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU); + + /* Set title font */ + SendDlgItemMessage( + hwndDlg, + IDC_WELCOMETITLE, + WM_SETFONT, + (WPARAM)DevInstData->hTitleFont, + (LPARAM)TRUE); + + SendDlgItemMessage( + hwndDlg, + IDC_DEVICE, + WM_SETTEXT, + 0, + (LPARAM)DevInstData->buffer); + + SendDlgItemMessage( + hwndDlg, + IDC_RADIO_AUTO, + BM_SETCHECK, + (WPARAM)TRUE, + (LPARAM)0); + break; + } + + case WM_NOTIFY: + { + LPNMHDR lpnm = (LPNMHDR)lParam; + + switch (lpnm->code) + { + case PSN_SETACTIVE: + /* Enable the Next button */ + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); + break; + + case PSN_WIZNEXT: + /* Handle a Next button click, if necessary */ + if (SendDlgItemMessage(hwndDlg, IDC_RADIO_AUTO, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_CHECKED) + PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV); + return TRUE; + + default: + break; + } + break; + } + + default: + break; + } + + return FALSE; +} + +static void +IncludePath(HWND Dlg, BOOL Enabled) +{ + EnableWindow(GetDlgItem(Dlg, IDC_COMBO_PATH), Enabled); + EnableWindow(GetDlgItem(Dlg, IDC_BROWSE), /*FIXME: Enabled*/ FALSE); +} + +static void +AutoDriver(HWND Dlg, BOOL Enabled) +{ + EnableWindow(GetDlgItem(Dlg, IDC_CHECK_MEDIA), Enabled); + EnableWindow(GetDlgItem(Dlg, IDC_CHECK_PATH), Enabled); + IncludePath(Dlg, Enabled & IsDlgButtonChecked(Dlg, IDC_CHECK_PATH)); +} + +static INT_PTR CALLBACK +CHSourceDlgProc( + IN HWND hwndDlg, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PDEVINSTDATA DevInstData; + + /* Retrieve pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA); + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND hwndControl; + DWORD dwStyle; + + /* Get pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; + SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData); + + hwndControl = GetParent(hwndDlg); + + /* Center the wizard window */ + CenterWindow(hwndControl); + + /* Hide the system menu */ + dwStyle = GetWindowLong(hwndControl, GWL_STYLE); + SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU); + + SendDlgItemMessage( + hwndDlg, + IDC_RADIO_SEARCHHERE, + BM_SETCHECK, + (WPARAM)TRUE, + (LPARAM)0); + AutoDriver(hwndDlg, TRUE); + IncludePath(hwndDlg, FALSE); + + /* Disable manual driver choice for now */ + EnableWindow(GetDlgItem(hwndDlg, IDC_RADIO_CHOOSE), FALSE); + /* Disable custom path for now */ + EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_PATH), FALSE); + break; + } + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_RADIO_SEARCHHERE: + AutoDriver(hwndDlg, TRUE); + return TRUE; + + case IDC_RADIO_CHOOSE: + AutoDriver(hwndDlg, FALSE); + return TRUE; + + case IDC_CHECK_PATH: + IncludePath(hwndDlg, IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH)); + return TRUE; + + case IDC_BROWSE: + /* FIXME: set the IDC_COMBO_PATH text */ + FIXME("Should display browse folder dialog\n"); + return FALSE; + } + break; + } + + case WM_NOTIFY: + { + LPNMHDR lpnm = (LPNMHDR)lParam; + + switch (lpnm->code) + { + case PSN_SETACTIVE: + /* Enable the Next and Back buttons */ + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK); + break; + + case PSN_WIZNEXT: + /* Handle a Next button click, if necessary */ + if (IsDlgButtonChecked(hwndDlg, IDC_RADIO_SEARCHHERE)) + { + HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath); + DevInstData->CustomSearchPath = NULL; + if (PrepareFoldersToScan(DevInstData, hwndDlg)) + PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV); + } + else + /* FIXME */; + return TRUE; + + default: + break; + } + break; + } + + default: + break; + } + + return FALSE; +} + +static INT_PTR CALLBACK +SearchDrvDlgProc( + IN HWND hwndDlg, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PDEVINSTDATA DevInstData; + DWORD dwThreadId; + + /* Retrieve pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA); + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND hwndControl; + DWORD dwStyle; + + /* Get pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; + SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData); + + DevInstData->hDialog = hwndDlg; + hwndControl = GetParent(hwndDlg); + + /* Center the wizard window */ + CenterWindow(hwndControl); + + SendDlgItemMessage( + hwndDlg, + IDC_DEVICE, + WM_SETTEXT, + 0, + (LPARAM)DevInstData->buffer); + + /* Hide the system menu */ + dwStyle = GetWindowLong(hwndControl, GWL_STYLE); + SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU); + break; + } + + case WM_SEARCH_FINISHED: + { + CloseHandle(hThread); + hThread = 0; + if (wParam == 0) + PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_NODRIVER); + else + PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_FINISHPAGE); + break; + } + + case WM_NOTIFY: + { + LPNMHDR lpnm = (LPNMHDR)lParam; + + switch (lpnm->code) + { + case PSN_SETACTIVE: + PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK); + hThread = CreateThread(NULL, 0, FindDriverProc, DevInstData, 0, &dwThreadId); + break; + + case PSN_KILLACTIVE: + if (hThread != 0) + { + SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE); + return TRUE; + } + break; + + case PSN_WIZNEXT: + /* Handle a Next button click, if necessary */ + break; + + default: + break; + } + break; + } + + default: + break; + } + + return FALSE; +} + +static INT_PTR CALLBACK +InstallDrvDlgProc( + IN HWND hwndDlg, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + return FALSE; +} + +static INT_PTR CALLBACK +NoDriverDlgProc( + IN HWND hwndDlg, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PDEVINSTDATA DevInstData; + + /* Get pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA); + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND hwndControl; + BOOL DisableableDevice = FALSE; + + DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; + SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData); + + hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL); + ShowWindow (hwndControl, SW_HIDE); + EnableWindow (hwndControl, FALSE); + + /* Set title font */ + SendDlgItemMessage( + hwndDlg, + IDC_FINISHTITLE, + WM_SETFONT, + (WPARAM)DevInstData->hTitleFont, + (LPARAM)TRUE); + + /* disable the "do not show this dialog anymore" checkbox + if the device cannot be disabled */ + CanDisableDevice( + DevInstData->devInfoData.DevInst, + NULL, + &DisableableDevice); + EnableWindow( + GetDlgItem(hwndDlg, IDC_DONOTSHOWDLG), + DisableableDevice); + break; + } + + case WM_NOTIFY: + { + LPNMHDR lpnm = (LPNMHDR)lParam; + + switch (lpnm->code) + { + case PSN_SETACTIVE: + /* Enable the correct buttons on for the active page */ + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH); + break; + + case PSN_WIZBACK: + /* Handle a Back button click, if necessary */ + PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_WELCOMEPAGE); + return TRUE; + + case PSN_WIZFINISH: + { + BOOL DisableableDevice = FALSE; + BOOL IsStarted = FALSE; + + if (CanDisableDevice(DevInstData->devInfoData.DevInst, + NULL, + &DisableableDevice) && + DisableableDevice && + IsDeviceStarted( + DevInstData->devInfoData.DevInst, + NULL, + &IsStarted) && + !IsStarted && + SendDlgItemMessage( + hwndDlg, + IDC_DONOTSHOWDLG, + BM_GETCHECK, + (WPARAM)0, (LPARAM)0) == BST_CHECKED) + { + /* disable the device */ + StartDevice( + DevInstData->hDevInfo, + &DevInstData->devInfoData, + FALSE, + 0, + NULL); + } + break; + } + + default: + break; + } + break; + } + + default: + break; + } + + return FALSE; +} + +static INT_PTR CALLBACK +FinishDlgProc( + IN HWND hwndDlg, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PDEVINSTDATA DevInstData; + + /* Retrieve pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA); + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND hwndControl; + + /* Get pointer to the global setup data */ + DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; + SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData); + + hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL); + ShowWindow (hwndControl, SW_HIDE); + EnableWindow (hwndControl, FALSE); + + SendDlgItemMessage( + hwndDlg, + IDC_DEVICE, + WM_SETTEXT, + 0, + (LPARAM)DevInstData->drvInfoData.Description); + + /* Set title font */ + SendDlgItemMessage( + hwndDlg, + IDC_FINISHTITLE, + WM_SETFONT, + (WPARAM)DevInstData->hTitleFont, + (LPARAM)TRUE); + break; + } + + case WM_NOTIFY: + { + LPNMHDR lpnm = (LPNMHDR)lParam; + + switch (lpnm->code) + { + case PSN_SETACTIVE: + /* Enable the correct buttons on for the active page */ + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH); + break; + + case PSN_WIZBACK: + /* Handle a Back button click, if necessary */ + break; + + case PSN_WIZFINISH: + /* Handle a Finish button click, if necessary */ + break; + + default: + break; + } + break; + } + + default: + break; + } + + return FALSE; +} + +static HFONT +CreateTitleFont(VOID) +{ + NONCLIENTMETRICS ncm; + LOGFONT LogFont; + HDC hdc; + INT FontSize; + HFONT hFont; + + ncm.cbSize = sizeof(NONCLIENTMETRICS); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); + + LogFont = ncm.lfMessageFont; + LogFont.lfWeight = FW_BOLD; + _tcscpy(LogFont.lfFaceName, _T("MS Shell Dlg")); + + hdc = GetDC(NULL); + FontSize = 12; + LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72; + hFont = CreateFontIndirect(&LogFont); + ReleaseDC(NULL, hdc); + + return hFont; +} + +BOOL +DisplayWizard( + IN PDEVINSTDATA DevInstData, + IN HWND hwndParent, + IN UINT startPage) +{ + PROPSHEETHEADER psh; + HPROPSHEETPAGE ahpsp[IDD_FINISHPAGE + 1]; + PROPSHEETPAGE psp; + + /* Create the Welcome page */ + ZeroMemory(&psp, sizeof(PROPSHEETPAGE)); + psp.dwSize = sizeof(PROPSHEETPAGE); + psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER; + psp.hInstance = hDllInstance; + psp.lParam = (LPARAM)DevInstData; + psp.pfnDlgProc = WelcomeDlgProc; + psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE); + ahpsp[IDD_WELCOMEPAGE] = CreatePropertySheetPage(&psp); + + /* Create the Select Source page */ + psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; + psp.pfnDlgProc = CHSourceDlgProc; + psp.pszTemplate = MAKEINTRESOURCE(IDD_CHSOURCE); + ahpsp[IDD_CHSOURCE] = CreatePropertySheetPage(&psp); + + /* Create the Search driver page */ + psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; + psp.pfnDlgProc = SearchDrvDlgProc; + psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHDRV); + ahpsp[IDD_SEARCHDRV] = CreatePropertySheetPage(&psp); + + /* Create the Install driver page */ + psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; + psp.pfnDlgProc = InstallDrvDlgProc; + psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLDRV); + ahpsp[IDD_INSTALLDRV] = CreatePropertySheetPage(&psp); + + /* Create the Install failed page */ + psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER; + psp.pfnDlgProc = NoDriverDlgProc; + psp.pszTemplate = MAKEINTRESOURCE(IDD_NODRIVER); + ahpsp[IDD_NODRIVER] = CreatePropertySheetPage(&psp); + + /* Create the Finish page */ + psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER; + psp.pfnDlgProc = FinishDlgProc; + psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE); + ahpsp[IDD_FINISHPAGE] = CreatePropertySheetPage(&psp); + + /* Create the property sheet */ + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER; + psh.hInstance = hDllInstance; + psh.hwndParent = hwndParent; + psh.nPages = 7; + psh.nStartPage = startPage; + psh.phpage = ahpsp; + psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); + psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER); + + /* Create title font */ + DevInstData->hTitleFont = CreateTitleFont(); + + /* Display the wizard */ + PropertySheet(&psh); + + DeleteObject(DevInstData->hTitleFont); + + return TRUE; +}