Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6117 lines
211 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
devwiz.c
Abstract:
Device Installer functions for install wizard support.
Author:
Lonny McMichael (lonnym) 22-Sep-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Define some macros to make the code a little cleaner.
//
//
// BOOL
// USE_CI_SELSTRINGS(
// IN PDEVINSTALL_PARAM_BLOCK p
// );
//
// This macro checks all the appropriate values to determine whether the
// class-installer provided strings may be used in the wizard.
//
#define USE_CI_SELSTRINGS(p) \
\
(((((p)->Flags) & (DI_USECI_SELECTSTRINGS | DI_CLASSINSTALLPARAMS)) == \
(DI_USECI_SELECTSTRINGS | DI_CLASSINSTALLPARAMS)) && \
(((p)->ClassInstallHeader->InstallFunction) == DIF_SELECTDEVICE))
//
// PTSTR
// GET_CI_SELSTRING(
// IN PDEVINSTALL_PARAM_BLOCK p,
// IN <FieldName> f
// );
//
// This macro retrieves a pointer to the specified string in a
// SP_SELECTDEVICE_PARAMS structure.
//
#define GET_CI_SELSTRINGS(p, f) \
\
(((PSP_SELECTDEVICE_PARAMS)((p)->ClassInstallHeader))->f)
//
// Definitions for timer used in device selection listboxes.
//
#define SELECTMFG_TIMER_ID 1
#define SELECTMFG_TIMER_DELAY 250
//
// Define a message sent from our auxilliary class driver search thread.
//
#define WMX_CLASSDRVLIST_DONE (WM_USER+131)
#define WMX_NO_DRIVERS_IN_LIST (WM_USER+132)
//
// HELP ID's
//
static const DWORD SelectDeviceShowAllHelpIDs[]=
{
IDC_NDW_PICKDEV_MFGLIST, IDH_DEVMGR_SELECTDEVICE_MANUFACTURER,
IDC_NDW_PICKDEV_ONEMFG_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
IDC_NDW_PICKDEV_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
IDC_NDW_STATUS_TEXT, IDH_NOHELP,
IDC_CLASSICON, IDH_NOHELP,
IDC_NDW_PICKDEV_COMPAT, IDH_DEVMGR_SELECTDEVICE_SHOWCOMPATIBLE,
IDC_NDW_PICKDEV_WINDOWSUPDATE, IDH_DEVMGR_SELECTDEVICE_WINDOWSUPDATE,
IDC_NDW_PICKDEV_HAVEDISK, IDH_DEVMGR_SELECTDEVICE_HAVEDISK,
IDC_NDW_TEXT, IDH_NOHELP,
IDD_DEVINSLINE, IDH_NOHELP,
0, 0
};
static const DWORD SelectDeviceShowSimilarHelpIDs[]=
{
IDC_NDW_PICKDEV_MFGLIST, IDH_DEVMGR_SELECTDEVICE_MANUFACTURER,
IDC_NDW_PICKDEV_ONEMFG_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
IDC_NDW_PICKDEV_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
IDC_NDW_STATUS_TEXT, IDH_NOHELP,
IDC_CLASSICON, IDH_NOHELP,
IDC_NDW_PICKDEV_COMPAT, IDH_DEVMGR_SELECTDEVICE_SHOWCOMPATIBLE,
IDC_NDW_PICKDEV_WINDOWSUPDATE, IDH_DEVMGR_SELECTDEVICE_WINDOWSUPDATE,
IDC_NDW_PICKDEV_HAVEDISK, IDH_DEVMGR_SELECTDEVICE_HAVEDISK,
IDC_NDW_TEXT, IDH_NOHELP,
IDD_DEVINSLINE, IDH_NOHELP,
0, 0
};
#define SELECTDEVICE_HELP TEXT("devmgr.hlp")
//
// Define structure containing class driver search context that is passed to
// an auxilliary thread while a Select Device dialog is displayed.
//
typedef struct _CLASSDRV_THREAD_CONTEXT {
HDEVINFO DeviceInfoSet;
SP_DEVINFO_DATA DeviceInfoData;
HWND NotificationWindow;
} CLASSDRV_THREAD_CONTEXT, *PCLASSDRV_THREAD_CONTEXT;
//
// Private function prototypes
//
DWORD
pSetupCreateNewDevWizData(
IN PSP_INSTALLWIZARD_DATA InstallWizardData,
OUT PNEWDEVWIZ_DATA *NewDeviceWizardData
);
UINT
CALLBACK
SelectDevicePropSheetPageProc(
IN HWND hwnd,
IN UINT uMsg,
IN LPPROPSHEETPAGE ppsp
);
INT_PTR
CALLBACK
SelectDeviceDlgProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
);
BOOL
InitSelectDeviceDlg(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
);
VOID
_OnSysColorChange(
HWND hWnd,
WPARAM wParam,
LPARAM lParam
);
BOOL
OnSetActive(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
);
DWORD
HandleSelectOEM(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
);
DWORD
HandleWindowsUpdate(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
);
DWORD
FillInDeviceList(
IN HWND hwndDlg,
IN PSP_DIALOGDATA lpdd
);
VOID
ShowListForMfg(
IN PSP_DIALOGDATA lpdd,
IN PDEVICE_INFO_SET DeviceInfoSet,
IN PDEVINSTALL_PARAM_BLOCK InstallParamBlock,
IN PDRIVER_NODE DriverNode, OPTIONAL
IN INT iMfg
);
VOID
LockAndShowListForMfg(
IN PSP_DIALOGDATA lpdd,
IN INT iMfg
);
PDRIVER_NODE
GetDriverNodeFromLParam(
IN PDEVICE_INFO_SET DeviceInfoSet,
IN PSP_DIALOGDATA lpdd,
IN LPARAM lParam
);
BOOL
pSetupIsSelectedHardwareIdValid(
IN HWND hWnd,
IN PSP_DIALOGDATA lpdd,
IN INT iCur
);
PDRIVER_NODE
pSetupGetSelectedDriverNode(
IN HWND hWnd,
IN PSP_DIALOGDATA lpdd,
IN INT iCur
);
VOID
SetSelectedDriverNode(
IN PSP_DIALOGDATA lpdd,
IN INT iCur
);
BOOL
bNoDevsToShow(
IN PDEVINFO_ELEM DevInfoElem
);
PNEWDEVWIZ_DATA
GetNewDevWizDataFromPsPage(
LPPROPSHEETPAGE ppsp
);
LONG
GetCurDesc(
IN PSP_DIALOGDATA lpdd
);
VOID
OnCancel(
IN PNEWDEVWIZ_DATA ndwData
);
VOID
__cdecl
ClassDriverSearchThread(
IN PVOID Context
);
BOOL
pSetupIsClassDriverListBuilt(
IN PSP_DIALOGDATA lpdd
);
VOID
pSetupDevInfoDataFromDialogData(
IN PSP_DIALOGDATA lpdd,
OUT PSP_DEVINFO_DATA DeviceInfoData
);
VOID
ToggleDialogControls(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData,
IN BOOL Enable
);
void
CleanupDriverLists(
IN OUT PNEWDEVWIZ_DATA ndwData
);
BOOL
CDMIsInternetAvailable(
void
);
HPROPSHEETPAGE
WINAPI
SetupDiGetWizardPage(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_INSTALLWIZARD_DATA InstallWizardData,
IN DWORD PageType,
IN DWORD Flags
)
/*++
Routine Description:
This routine retrieves a handle to one of the Setup API-provided wizard
pages, for an application to include in its own wizard.
Arguments:
DeviceInfoSet - Supplies the handle of the device information set to
retrieve a wizard page for.
DeviceInfoData - Optionally, supplies the address of a device information
with which the wizard page will be associated. This parameter is only
used if the flags parameter includes DIWP_FLAG_USE_DEVINFO_DATA. If that
flag is set, and if this parameter is not specified, then the wizard
page will be associated with the global class driver list.
InstallWizardData - Supplies the address of a PSP_INSTALLWIZARD_DATA
structure containing parameters to be used by this wizard page. The
cbSize field must be set to the size of the structure, in bytes, or the
structure will be considered invalid.
PageType - Supplies an ordinal indicating the type of wizard page to be retreived.
May be one of the following values:
SPWPT_SELECTDEVICE - Retrieve a select device wizard page.
Flags - Supplies flags that specify how the wizard page is to be created.
May be a combination of the following values:
SPWP_USE_DEVINFO_DATA - Use the device information element specified
by DeviceInfoData, or use the global class
driver list if DeviceInfoData is not supplied.
If this flag is not supplied, the wizard page
will act upon the currently selected device
(as selected by SetupDiSetSelectedDevice), or
upon the global class driver list if no device
is selected.
Return Value:
If the function succeeds, the return value is the handle to the requested
wizard page.
If the function fails, the return value is NULL. To get extended error
information, call GetLastError.
Remarks:
A device information set may not be destroyed as long as there are any active wizard
pages using it. In addition, if the wizard page is associated with a particular device
information element, then that element will not be deletable as long as it is being
used by a wizard page.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
DWORD Err = NO_ERROR;
HPROPSHEETPAGE hPage = NULL;
PNEWDEVWIZ_DATA ndwData = NULL;
PWIZPAGE_OBJECT WizPageObject = NULL;
//
// Store the address of the corresponding wizard object at the
// end of the PROPSHEETPAGE buffer.
//
BYTE pspBuffer[sizeof(PROPSHEETPAGE) + sizeof(PVOID)];
LPPROPSHEETPAGE Page = (LPPROPSHEETPAGE)pspBuffer;
//
// Make sure we're running interactively.
//
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return FALSE;
}
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
try {
switch(PageType) {
case SPWPT_SELECTDEVICE :
Page->pszTemplate = MAKEINTRESOURCE(IDD_DYNAWIZ_SELECTDEV_PAGE);
Page->pfnDlgProc = SelectDeviceDlgProc;
Page->pfnCallback = SelectDevicePropSheetPageProc;
#ifndef ANSI_SETUPAPI
Page->pszHeaderTitle = MAKEINTRESOURCE(IDS_NDW_SELECTDEVICE);
Page->pszHeaderSubTitle = NULL;
#endif
break;
default :
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// Validate the supplied InstallWizardData structure, and create a private
// storage buffer for internal use by the wizard page.
//
if((Err = pSetupCreateNewDevWizData(InstallWizardData, &ndwData)) != NO_ERROR) {
goto clean0;
}
//
// Store the device information set handle in the dialogdata structure
// embedded in the New Device Wizard buffer.
//
ndwData->ddData.DevInfoSet = DeviceInfoSet;
//
// If the caller specified the SPWP_USE_DEVINFO_DATA flag, then store information
// in the dialog data structure about the specified devinfo element (if supplied).
//
if(Flags & SPWP_USE_DEVINFO_DATA) {
if(DeviceInfoData) {
//
// Verify that the specified device information element is a valid one.
//
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL))) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
} else if(DevInfoElem->DiElemFlags & DIE_IS_LOCKED) {
//
// Device information element cannot be explicitly used by more than
// one wizard page at a time.
//
Err = ERROR_DEVINFO_DATA_LOCKED;
goto clean0;
}
DevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
ndwData->ddData.DevInfoElem = DevInfoElem;
}
ndwData->ddData.flags = DD_FLAG_USE_DEVINFO_ELEM;
}
//
// We've successfully created and initialized the devwiz data structure.
// Now create a wizpage object so we can keep track of it.
//
if(WizPageObject = MyMalloc(sizeof(WIZPAGE_OBJECT))) {
WizPageObject->RefCount = 0;
WizPageObject->ndwData = ndwData;
//
// Insert this new object into the devinfo set's wizard object list.
//
WizPageObject->Next = pDeviceInfoSet->WizPageList;
pDeviceInfoSet->WizPageList = WizPageObject;
} else {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
Page->dwSize = sizeof(pspBuffer);
#ifndef ANSI_SETUPAPI
Page->dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE | PSP_USECALLBACK | PSP_USEFUSIONCONTEXT;
Page->hActCtx = NULL;
#else
Page->dwFlags = PSP_DEFAULT | PSP_USECALLBACK;
#endif
Page->hInstance = MyDllModuleHandle;
Page->lParam = (LPARAM)DeviceInfoSet;
*((PVOID *)(&(pspBuffer[sizeof(PROPSHEETPAGE)]))) = WizPageObject;
if(!(hPage = CreatePropertySheetPage(Page))) {
Err = ERROR_INVALID_DATA;
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
if(Err != NO_ERROR) {
if(ndwData) {
MyFree(ndwData);
}
if(WizPageObject) {
MyFree(WizPageObject);
}
}
SetLastError(Err);
return hPage;
}
BOOL
WINAPI
SetupDiGetSelectedDevice(
IN HDEVINFO DeviceInfoSet,
OUT PSP_DEVINFO_DATA DeviceInfoData
)
/*++
Routine Description:
This routine retrieves the currently-selected device for the specified
device information set. This is typically used during an installation
wizard.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set for
which the selected device is to be retrieved.
DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure
that receives the currently-selected device. If there is no device
currently selected, then the routine will fail, and GetLastError
will return ERROR_NO_DEVICE_SELECTED.
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
DWORD Err;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
if(pDeviceInfoSet->SelectedDevInfoElem) {
if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
pDeviceInfoSet->SelectedDevInfoElem,
DeviceInfoData))) {
Err = ERROR_INVALID_USER_BUFFER;
}
} else {
Err = ERROR_NO_DEVICE_SELECTED;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
SetLastError(Err);
return(Err == NO_ERROR);
}
BOOL
WINAPI
SetupDiSetSelectedDevice(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData
)
/*++
Routine Description:
This routine sets the specified device information element to be the
currently selected member of a device information set. This is typically
used during an installation wizard.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set for
which the selected device is to be set.
DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure
specifying the device information element to be selected.
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
DWORD Err;
PDEVINFO_ELEM DevInfoElem;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet, DeviceInfoData, NULL)) {
pDeviceInfoSet->SelectedDevInfoElem = DevInfoElem;
} else {
Err = ERROR_INVALID_PARAMETER;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
SetLastError(Err);
return(Err == NO_ERROR);
}
DWORD
pSetupCreateNewDevWizData(
IN PSP_INSTALLWIZARD_DATA InstallWizardData,
OUT PNEWDEVWIZ_DATA *NewDeviceWizardData
)
/*++
Routine Description:
This routine validates an InstallWizardData buffer, then allocates and
fills in a NEWDEVWIZ_DATA buffer based on information supplied therein.
Arguments:
InstallWizardData - Supplies the address of an installation wizard data
structure to be validated and used in building the private buffer.
NewDeviceWizardData - Supplies the address of a variable that receives a pointer
to the newly-allocated install wizard data buffer.
Return Value:
If the function succeeds, the return value is NO_ERROR, otherwise, it is
an ERROR_* code.
--*/
{
PNEWDEVWIZ_DATA ndwData = NULL;
DWORD Err = NO_ERROR;
if((InstallWizardData->ClassInstallHeader.cbSize != sizeof(SP_CLASSINSTALL_HEADER)) ||
(InstallWizardData->ClassInstallHeader.InstallFunction != DIF_INSTALLWIZARD)) {
return ERROR_INVALID_USER_BUFFER;
}
//
// The dynamic page entries are currently ignored, as are the Private
// fields. Also, the hwndWizardDlg is not validated.
//
try {
if(ndwData = MyMalloc(sizeof(NEWDEVWIZ_DATA))) {
ZeroMemory(ndwData, sizeof(NEWDEVWIZ_DATA));
} else {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
//
// Initialize the Current Description string table index in the dialog data
// to -1, so that it will get updated when the wizard page is first entered.
//
ndwData->ddData.iCurDesc = -1;
//
// Copy the installwizard data.
//
CopyMemory(&(ndwData->InstallData),
InstallWizardData,
sizeof(SP_INSTALLWIZARD_DATA)
);
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
if((Err != NO_ERROR) && ndwData) {
MyFree(ndwData);
} else {
*NewDeviceWizardData = ndwData;
}
return Err;
}
UINT
CALLBACK
SelectDevicePropSheetPageProc(
IN HWND hwnd,
IN UINT uMsg,
IN LPPROPSHEETPAGE ppsp
)
/*++
Routine Description:
This routine is called when the Select Device wizard page is created or destroyed.
Arguments:
hwnd - Reserved
uMsg - Action flag, either PSPCB_CREATE or PSPCB_RELEASE
ppsp - Supplies the address of the PROPSHEETPAGE structure being created or destroyed.
Return Value:
If uMsg is PSPCB_CREATE, then return non-zero to allow the page to be created, or
zero to prevent it.
if uMsg is PSPCB_RELEASE, the return value is ignored.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
UINT ret;
PVOID WizObjectId;
PWIZPAGE_OBJECT CurWizObject, PrevWizObject;
//
// Access the device info set handle stored in the propsheetpage's lParam.
//
if(!(pDeviceInfoSet = AccessDeviceInfoSet((HDEVINFO)(ppsp->lParam)))) {
return FALSE;
}
ret = TRUE;
try {
//
// The ObjectID (pointer, actually) for the corresponding wizard
// object for this page is stored at the end of the ppsp structure.
// Retrieve this now, and look for it in the devinfo set's list of
// wizard objects.
//
WizObjectId = *((PVOID *)(&(((PBYTE)ppsp)[sizeof(PROPSHEETPAGE)])));
for(CurWizObject = pDeviceInfoSet->WizPageList, PrevWizObject = NULL;
CurWizObject;
PrevWizObject = CurWizObject, CurWizObject = CurWizObject->Next) {
if(WizObjectId == CurWizObject) {
//
// We found our object.
//
break;
}
}
if(!CurWizObject) {
ret = FALSE;
goto clean0;
}
switch(uMsg) {
case PSPCB_CREATE :
//
// Fail the create if we've already been created once (hopefully, this
// will never happen).
//
if(CurWizObject->RefCount) {
ret = FALSE;
goto clean0;
} else {
CurWizObject->RefCount++;
}
break;
case PSPCB_RELEASE :
//
// Decrement the wizard object refcount. If it goes to zero (or if it
// already was zero because we never got a PSPCB_CREATE message), then
// remove the object from the linked list, and free all associated memory.
//
if(CurWizObject->RefCount) {
CurWizObject->RefCount--;
}
MYASSERT(!CurWizObject->RefCount);
if(!CurWizObject->RefCount) {
//
// Remove the object from the object list.
//
if(PrevWizObject) {
PrevWizObject->Next = CurWizObject->Next;
} else {
pDeviceInfoSet->WizPageList = CurWizObject->Next;
}
//
// If this wizard object was explicitly tied to a particular device
// information element, then unlock that element now.
//
if((CurWizObject->ndwData->ddData.flags & DD_FLAG_USE_DEVINFO_ELEM) &&
(DevInfoElem = CurWizObject->ndwData->ddData.DevInfoElem)) {
MYASSERT(DevInfoElem->DiElemFlags & DIE_IS_LOCKED);
DevInfoElem->DiElemFlags ^= DIE_IS_LOCKED;
}
MyFree(CurWizObject->ndwData);
MyFree(CurWizObject);
}
}
clean0: ; // nothing to do
} except(EXCEPTION_EXECUTE_HANDLER) {
ret = FALSE;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
return ret;
}
INT_PTR
CALLBACK
SelectDeviceDlgProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
This is the dialog proc for the Select Device wizard page.
--*/
{
INT iCur;
HICON hicon;
PNEWDEVWIZ_DATA ndwData;
PSP_INSTALLWIZARD_DATA iwd;
LV_ITEM lvItem;
TCHAR TempString[LINE_LEN];
PCLASSDRV_THREAD_CONTEXT ClassDrvThreadContext;
HCURSOR hOldCursor;
if(uMsg == WM_INITDIALOG) {
LPPROPSHEETPAGE Page = (LPPROPSHEETPAGE)lParam;
//
// Retrieve a pointer to the device wizard data associated with
// this wizard page.
//
ndwData = GetNewDevWizDataFromPsPage(Page);
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ndwData);
if(ndwData) {
ndwData->bInit = TRUE;
ndwData->idTimer = 0;
ndwData->bInit = FALSE;
} else {
//
// This is really bad--we can't simply call EndDialog() since we
// don't know whether we're a dialog or a wizard page. This should
// never happen.
//
return TRUE; // we didn't set the focus
}
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
//
// For the stand-alone dialog box version, we initialize here.
//
ndwData->bInit = TRUE; // Still doing some init stuff
//
// Make sure our "waiting for class list" static text control is hidden!
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
if (!InitSelectDeviceDlg(hwndDlg, ndwData)) {
//
// We don't have any items displayed so ask the user if they want
// to go directly to Have Disk, or just cancel.
//
PostMessage(hwndDlg, WMX_NO_DRIVERS_IN_LIST, 0, 0);
}
ndwData->bInit = FALSE; // Done with init stuff
return FALSE; // we already set the focus.
} else {
return TRUE; // we didn't set the focus
}
} else {
//
// For the small set of messages that we get before WM_INITDIALOG, we
// won't have a devwizdata pointer!
//
if(ndwData = (PNEWDEVWIZ_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER)) {
iwd = &(ndwData->InstallData);
} else {
//
// If we haven't gotten a WM_INITDIALOG message yet, or if for some reason
// we weren't able to retrieve the ndwData pointer when we did, then we
// simply return FALSE for all messages.
//
// (If we ever need to process messages before WM_INITDIALOG (e.g., set font),
// then we'll need to modify this approach.)
//
return FALSE;
}
}
switch(uMsg) {
case WMX_CLASSDRVLIST_DONE :
MYASSERT(ndwData->ddData.AuxThreadRunning);
ndwData->ddData.AuxThreadRunning = FALSE;
//
// wParam is a boolean indicating the result of the class driver search.
// lParam is NO_ERROR upon success, or a Win32 error code indicating cause of failure.
//
switch(ndwData->ddData.PendingAction) {
case PENDING_ACTION_NONE :
//
// Then the thread has completed, but the user is still mulling over the
// choices on the compatible driver list. If the class driver list was
// successfully built, then there's nothing to do here. If it failed for
// some reason (highly unlikely), then we (silently) disable the
// 'show compatible devices' check box.
if(!wParam) {
ndwData->ddData.flags |= DD_FLAG_CLASSLIST_FAILED;
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
}
break;
case PENDING_ACTION_SELDONE :
//
// In this case, we don't care what happened in the other thread. The
// user has made their selection, and we're ready to return success.
//
SetSelectedDriverNode(&(ndwData->ddData),
ndwData->ddData.CurSelectionForSuccess
);
EndDialog(hwndDlg, NO_ERROR);
break;
case PENDING_ACTION_SHOWCLASS :
//
// Then we've been waiting on the class driver search to complete, so that
// we can show the list. Hopefully, the search was successful. If not,
// we'll give the user a popup saying that the list could not be shown, and
// then leave them in the compatible list view (with the class list radio
// button now disabled).
//
ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
if(wParam) {
//
// The class driver list was built successfully.
//
if(ndwData->ddData.CurSelectionForSuccess != LB_ERR) {
lvItem.mask = LVIF_TEXT;
lvItem.iItem = ndwData->ddData.CurSelectionForSuccess;
lvItem.iSubItem = 0;
lvItem.pszText = TempString;
lvItem.cchTextMax = SIZECHARS(TempString);
if(ListView_GetItem((ndwData->ddData).hwndDrvList, &lvItem)) {
//
// Now retrieve the (case-insensitive) string ID of this
// string, and store it as the current description ID.
//
(ndwData->ddData).iCurDesc = LookUpStringInDevInfoSet((ndwData->ddData).DevInfoSet,
TempString,
FALSE
);
}
}
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
if(FillInDeviceList(hwndDlg, &(ndwData->ddData)) == NO_ERROR) {
//
// Enable the OK/Next button
//
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
}
}
break;
}
}
//
// Inform the user that the class driver search failed.
//
if(!LoadString(MyDllModuleHandle,
IDS_SELECT_DEVICE,
TempString,
SIZECHARS(TempString))) {
*TempString = TEXT('\0');
}
FormatMessageBox(MyDllModuleHandle,
hwndDlg,
MSG_NO_CLASSDRVLIST_ERROR,
TempString,
MB_OK | MB_TASKMODAL
);
//
// Check the 'Show compatible devices' check box and then gray
// it out since the user cannot uncheck it since we don't have
// a class list.
//
CheckDlgButton(hwndDlg, IDC_NDW_PICKDEV_COMPAT, BST_CHECKED);
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
ndwData->ddData.bShowCompat = TRUE;
ndwData->ddData.flags |= DD_FLAG_CLASSLIST_FAILED;
//
// We also must unhide the compatible driver list controls, and re-enable
// the OK button.
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
}
}
break;
case PENDING_ACTION_CANCEL :
//
// This is an easy one. No matter what happened in the other thread,
// we simply want to clean up and return.
//
OnCancel(ndwData);
EndDialog(hwndDlg, ERROR_CANCELLED);
break;
case PENDING_ACTION_OEM :
case PENDING_ACTION_WINDOWSUPDATE:
//
// The user clicked the "Have Disk" button or the "Windows Update" button.
// Pass this off to either HandleSelectOEM() or HandleWindowsUpdate().
// If we get back success, then we are done, and can end the dialog.
//
if(((ndwData->ddData.PendingAction == PENDING_ACTION_OEM) &&
(HandleSelectOEM(hwndDlg, ndwData) == NO_ERROR)) ||
((ndwData->ddData.PendingAction == PENDING_ACTION_WINDOWSUPDATE) &&
(HandleWindowsUpdate(hwndDlg, ndwData) == NO_ERROR))) {
ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EndDialog(hwndDlg, NO_ERROR);
} else {
iwd->Flags |= NDW_INSTALLFLAG_CI_PICKED_OEM;
PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
}
} else {
//
// The OEM selection was not made, so we'll just continue as though
// nothing had happened. Re-enable the dialog/wizard controls.
//
ToggleDialogControls(hwndDlg, ndwData, TRUE);
if (ndwData->ddData.bShowCompat) {
ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
} else {
ndwData->ddData.PendingAction = PENDING_ACTION_SHOWCLASS;
}
ndwData->bInit = FALSE;
//
// We got here by aborting the class driver search. Since we may need
// it after all, we must re-start the search (unless the auxilliary thread
// happened to have already finished before we sent it the abort request).
//
if(!(ndwData->ddData.flags & DD_FLAG_CLASSLIST_FAILED) &&
!pSetupIsClassDriverListBuilt(&(ndwData->ddData)))
{
//
// Allocate a context structure to pass to the auxilliary thread (the
// auxilliary thread will take care of freeing the memory).
//
if(ClassDrvThreadContext = MyMalloc(sizeof(CLASSDRV_THREAD_CONTEXT))) {
//
// Fill in the context structure, and fire off the thread.
//
ClassDrvThreadContext->DeviceInfoSet = ndwData->ddData.DevInfoSet;
//
// SP_DEVINFO_DATA can only be retrieved whilst the device information
// set is locked.
//
pSetupDevInfoDataFromDialogData(&(ndwData->ddData),
&(ClassDrvThreadContext->DeviceInfoData)
);
ClassDrvThreadContext->NotificationWindow = hwndDlg;
if(_beginthread(ClassDriverSearchThread, 0, ClassDrvThreadContext) == -1) {
MyFree(ClassDrvThreadContext);
} else {
ndwData->ddData.AuxThreadRunning = TRUE;
//
// If we're currently in the class driver list view, then disable
// the OK/Next button, since the user can't select a class driver yet.
//
if (!ndwData->ddData.bShowCompat) {
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
}
}
}
}
}
if(!(ndwData->ddData.AuxThreadRunning)) {
//
// We couldn't start the class driver search thread.
// check and disable the 'Show compatible devices'
// check box.
//
if (!ndwData->ddData.bShowCompat) {
CheckDlgButton(hwndDlg,
IDC_NDW_PICKDEV_COMPAT,
BST_CHECKED
);
}
ndwData->ddData.flags |= DD_FLAG_CLASSLIST_FAILED;
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
}
}
}
break;
}
break;
case WMX_NO_DRIVERS_IN_LIST: {
TCHAR Title[LINE_LEN];
if(!LoadString(MyDllModuleHandle, IDS_SELECT_DEVICE, Title, SIZECHARS(Title))) {
Title[0]=TEXT('\0');
}
if(!LoadString(MyDllModuleHandle, IDS_NDW_NODRIVERS_WARNING, TempString, SIZECHARS(TempString))) {
TempString[0]=TEXT('\0');
}
if (IDOK == MessageBox(hwndDlg, TempString, Title, MB_OKCANCEL | MB_ICONEXCLAMATION)) {
PostMessage(hwndDlg, WM_COMMAND, IDC_NDW_PICKDEV_HAVEDISK, 0);
} else {
PostMessage(hwndDlg, WM_COMMAND, IDCANCEL, 0);
}
break;
}
case WM_DESTROY:
if(ndwData->ddData.AuxThreadRunning) {
//
// This should never happen. But just to be on the safe side, if it does,
// we'll cancel the search. We _will not_ however, wait for the
// WMX_CLASSDRVLIST_DONE message, to signal that the thread has terminated.
// This should be OK, since the worst that can happen is that it will try
// to send a message to a window that no longer exists.
//
SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
}
if(ndwData->idTimer) {
ndwData->bInit = TRUE;
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
}
if(hicon = (HICON)SendDlgItemMessage(hwndDlg, IDC_CLASSICON, STM_GETICON, 0, 0)) {
DestroyIcon(hicon);
}
if(hicon = (HICON)SendDlgItemMessage(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON, STM_GETICON, 0, 0)) {
DestroyIcon(hicon);
}
if (ndwData->ddData.hImageList) {
ImageList_Destroy(ndwData->ddData.hImageList);
}
if (ndwData->ddData.hFontNormal) {
DeleteObject(ndwData->ddData.hFontNormal);
}
if (ndwData->ddData.hFontBold) {
DeleteObject(ndwData->ddData.hFontBold);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_NDW_PICKDEV_COMPAT:
if((HIWORD(wParam) == BN_CLICKED) &&
IsWindowVisible(GetDlgItem(hwndDlg, LOWORD(wParam)))) {
ndwData->ddData.bShowCompat = IsDlgButtonChecked(hwndDlg, IDC_NDW_PICKDEV_COMPAT);
//
// Update the current description ID in the dialog data so that
// the same device will be highlighted when we switch from one
// view to the other.
//
iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
-1,
LVNI_SELECTED
);
if(ndwData->ddData.AuxThreadRunning) {
//
// There are two possibilities here:
//
// 1. The user was looking at the compatible driver list, and then
// decided to look at the class driver list, which we're not done
// building yet. In that case, hide the compatible driver listbox,
// and unhide our "waiting for class list" static text control.
//
// 2. The user switched to the class driver list view, saw that we
// were still working on it, and then decided to switch back to
// the compatible list. In that case, we simply need to re-hide
// the "waiting for class list" static text control, and show
// the compatible driver listbox again. In this case, we don't
// want to attempt to re-initialize the listbox, as that will
// require acquiring the HDEVINFO lock, and we will hang.
//
if(ndwData->ddData.bShowCompat) {
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_SHOW);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_SHOW);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_SHOW);
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
}
}
//
// We no longer have a pending action.
//
ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
} else {
//
// Temporarily hide the compatible driver listbox, and unhide the
// "waiting for class list" static text control.
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_SHOW);
if(!LoadString(MyDllModuleHandle, IDS_NDW_RETRIEVING_LIST, TempString, SIZECHARS(TempString))) {
TempString[0]=TEXT('\0');
}
SetDlgItemText(hwndDlg, IDC_NDW_STATUS_TEXT, TempString);
//
// Disable the OK/Next button, because the user can't select a class driver
// yet.
//
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
}
}
MYASSERT(ndwData->ddData.PendingAction == PENDING_ACTION_NONE);
ndwData->ddData.PendingAction = PENDING_ACTION_SHOWCLASS;
ndwData->ddData.CurSelectionForSuccess = iCur;
}
} else {
if(iCur != LB_ERR) {
lvItem.mask = LVIF_TEXT;
lvItem.iItem = iCur;
lvItem.iSubItem = 0;
lvItem.pszText = TempString;
lvItem.cchTextMax = SIZECHARS(TempString);
if(ListView_GetItem((ndwData->ddData).hwndDrvList, &lvItem)) {
//
// Now retrieve the (case-insensitive) string ID of this
// string, and store it as the current description ID.
//
(ndwData->ddData).iCurDesc = LookUpStringInDevInfoSet((ndwData->ddData).DevInfoSet,
TempString,
FALSE
);
}
}
FillInDeviceList(hwndDlg, &(ndwData->ddData));
//
// If we just filled in the compatible driver list,
// then make sure there isn't a timer waiting to
// pounce and destroy our list!
//
if((ndwData->ddData.bShowCompat) &&
(ndwData->idTimer)) {
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
ndwData->idTimer = 0;
}
}
}
break;
case IDC_NDW_PICKDEV_HAVEDISK :
//
// If we're doing a dialog box, then pressing "Have Disk" will popup another
// Select Device dialog. Disable all controls on this one first, to avoid
// user confusion.
//
ToggleDialogControls(hwndDlg, ndwData, FALSE);
//
// If HandleSelectOEM returns success, we are done, and can either end
// the dialog, or proceed to the next wizard page.
//
if(ndwData->ddData.AuxThreadRunning) {
//
// The auxilliary thread is still running. Set our cursor to an
// hourglass, and set our pending action to be OEM Select while we
// wait for the thread to respond to our cancel request.
//
MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
(ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
//
// Disable all dialog controls, so that no other button may be pressed
// until we respond to this pending action. Also, kill the timer, so
// that it doesn't fire in the meantime.
//
ndwData->bInit = TRUE;
if(ndwData->idTimer) {
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
ndwData->idTimer = 0;
}
ndwData->ddData.PendingAction = PENDING_ACTION_OEM;
SetCursor(hOldCursor);
} else {
if(HandleSelectOEM(hwndDlg, ndwData) == NO_ERROR) {
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EndDialog(hwndDlg, NO_ERROR);
} else {
iwd->Flags |= NDW_INSTALLFLAG_CI_PICKED_OEM;
PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
}
} else {
//
// The user didn't make an OEM selection, so we need to re-enable
// the controls on our dialog/wizard.
//
ToggleDialogControls(hwndDlg, ndwData, TRUE);
}
}
break;
case IDC_NDW_PICKDEV_WINDOWSUPDATE:
//
// If we're doing a dialog box, then pressing "Have Disk" will popup another
// Select Device dialog. Disable all controls on this one first, to avoid
// user confusion.
//
ToggleDialogControls(hwndDlg, ndwData, FALSE);
//
// If HandleWindowsUpdate returns success, we are done, and can either end
// the dialog, or proceed to the next wizard page.
//
if(ndwData->ddData.AuxThreadRunning) {
//
// The auxilliary thread is still running. Set our cursor to an
// hourglass, and set our pending action to be Windows Update Select while we
// wait for the thread to respond to our cancel request.
//
MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
(ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
//
// Disable all dialog controls, so that no other button may be pressed
// until we respond to this pending action. Also, kill the timer, so
// that it doesn't fire in the meantime.
//
ndwData->bInit = TRUE;
if(ndwData->idTimer) {
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
ndwData->idTimer = 0;
}
ndwData->ddData.PendingAction = PENDING_ACTION_WINDOWSUPDATE;
SetCursor(hOldCursor);
} else {
if(HandleWindowsUpdate(hwndDlg, ndwData) == NO_ERROR) {
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EndDialog(hwndDlg, NO_ERROR);
} else {
iwd->Flags |= NDW_INSTALLFLAG_CI_PICKED_OEM;
PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
}
} else {
//
// The user didn't make an OEM selection, so we need to re-enable
// the controls on our dialog.
//
ToggleDialogControls(hwndDlg, ndwData, TRUE);
}
}
break;
case IDOK :
HandleOK:
iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
-1,
LVNI_SELECTED
);
if(iCur != LB_ERR) {
//
// We have retrieved a valid selection from our listbox.
//
if(ndwData->ddData.AuxThreadRunning) {
//
// The auxilliary thread is still running. Set our cursor to an
// hourglass, while we wait for the thread to terminate.
//
MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
(ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
//
// Disable all dialog controls, so that no other button may be pressed
// until we respond to this pending action. Also, kill the timer, so
// that it doesn't fire in the meantime.
//
ToggleDialogControls(hwndDlg, ndwData, FALSE);
ndwData->bInit = TRUE;
if(ndwData->idTimer) {
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
ndwData->idTimer = 0;
}
ndwData->ddData.PendingAction = PENDING_ACTION_SELDONE;
ndwData->ddData.CurSelectionForSuccess = iCur;
SetCursor(hOldCursor);
} else {
//
// The auxilliary thread has already returned. We can return
// success right here.
//
SetSelectedDriverNode(&(ndwData->ddData), iCur);
EndDialog(hwndDlg, NO_ERROR);
}
} else {
//
// If the list box is empty, then just leave. We will treat this
// just like the user canceled.
//
if (0 == ListView_GetItemCount((ndwData->ddData).hwndDrvList)) {
PostMessage(hwndDlg, WM_COMMAND, IDCANCEL, 0);
} else {
//
// Tell user to select something since there are items in the list
//
if(!LoadString(MyDllModuleHandle,
IDS_SELECT_DEVICE,
TempString,
SIZECHARS(TempString))) {
*TempString = TEXT('\0');
}
FormatMessageBox(MyDllModuleHandle,
hwndDlg,
MSG_SELECTDEVICE_ERROR,
TempString,
MB_OK | MB_ICONEXCLAMATION
);
}
}
break;
case IDCANCEL :
if(ndwData->ddData.AuxThreadRunning) {
//
// The auxilliary thread is running, so we have to ask it to cancel,
// and set our pending action to do the cancel upon the thread's
// termination notification.
//
MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
(ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
//
// Disable all dialog controls, so that no other button may be pressed
// until we respond to this pending action. Also, kill the timer, so
// that it doesn't fire in the meantime.
//
ToggleDialogControls(hwndDlg, ndwData, FALSE);
ndwData->bInit = TRUE;
if(ndwData->idTimer) {
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
ndwData->idTimer = 0;
}
ndwData->ddData.PendingAction = PENDING_ACTION_CANCEL;
SetCursor(hOldCursor);
} else {
//
// The auxilliary thread isn't running, so we can return right here.
//
OnCancel(ndwData);
EndDialog(hwndDlg, ERROR_CANCELLED);
}
break;
default :
return FALSE;
}
break;
case WM_NOTIFY :
switch(((LPNMHDR)lParam)->code) {
case PSN_SETACTIVE :
//
// Init the text in set active since a class installer
// has the option of replacing it.
//
SetDlgText(hwndDlg, IDC_NDW_TEXT, IDS_NDW_PICKDEV1, IDS_NDW_PICKDEV1);
ndwData->bInit = TRUE; // Still doing some init stuff
if(!OnSetActive(hwndDlg, ndwData)) {
SetDlgMsgResult(hwndDlg, uMsg, -1);
}
ndwData->bInit = FALSE; // Done with init stuff
break;
case PSN_WIZBACK :
CleanupDriverLists(ndwData);
if(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED) {
SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_SELECT_PREVPAGE);
} else {
SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_SELECTCLASS_PAGE);
}
break;
case PSN_WIZNEXT :
if(!(iwd->Flags & NDW_INSTALLFLAG_CI_PICKED_OEM)) {
iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
-1,
LVNI_SELECTED
);
if(iCur != LB_ERR) {
//
// We have retrieved a valid selection from our listbox.
//
if (pSetupIsSelectedHardwareIdValid(hwndDlg, &(ndwData->ddData), iCur)) {
SetSelectedDriverNode(&(ndwData->ddData), iCur);
} else {
SetDlgMsgResult(hwndDlg, uMsg, (LRESULT)-1);
break;
}
} else { // Invalid Listview selection
//
// Fail the call and end the case
//
SetDlgMsgResult(hwndDlg, uMsg, (LRESULT)-1);
break;
}
}
//
// Update the current description in the dialog data so that we'll hi-lite
// the correct selection if the user comes back to this page.
//
(ndwData->ddData).iCurDesc = GetCurDesc(&(ndwData->ddData));
if(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED) {
SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_SELECT_NEXTPAGE);
} else {
SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_ANALYZEDEV_PAGE);
}
break;
case LVN_ITEMCHANGED :
//
// If the idFrom is the MFG list, then update the Drv list.
//
if(((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_MFGLIST) && !ndwData->bInit) {
if(ndwData->idTimer) {
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
}
ndwData->idTimer = SetTimer(hwndDlg,
SELECTMFG_TIMER_ID,
SELECTMFG_TIMER_DELAY,
NULL
);
if(ndwData->idTimer == 0) {
goto SelectMfgItemNow;
}
}
//
// If the idFrom is either of the model lists then update
// the digital signature icon and text.
//
if (((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_ONEMFG_DRVLIST) ||
((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_DRVLIST)) {
LVITEM lviItem;
int iImage = -1;
hicon = NULL;
iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
-1,
LVNI_SELECTED
);
if(iCur != -1) {
//
// We have retrieved a valid selection from our listbox.
//
lviItem.mask = LVIF_IMAGE;
lviItem.iItem = iCur;
lviItem.iSubItem = 0;
if(ListView_GetItem((ndwData->ddData).hwndDrvList, &lviItem)) {
iImage = lviItem.iImage;
}
}
if (iImage != -1) {
//
// Enable the OK/Next button, because the user can't select a class driver
// yet.
//
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
}
}
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_SHOW);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_SHOW);
//
// Don't show the link if we are in GUI setup because
// help center is not installed yet and so clicking
// on the link won't do anything.
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK),
GuiSetupInProgress ? SW_HIDE : SW_SHOW);
if (iImage == IMAGE_ICON_SIGNED) {
//
// Load the digital signature icon and text
//
hicon = LoadImage(MyDllModuleHandle,
MAKEINTRESOURCE(IDI_SIGNED),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0
);
if(!LoadString(MyDllModuleHandle,
IDS_DRIVER_IS_SIGNED,
TempString,
SIZECHARS(TempString))) {
*TempString = TEXT('\0');
}
if ((ndwData->ddData).hFontNormal) {
SetWindowFont(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), (ndwData->ddData).hFontNormal, TRUE);
}
} else {
//
// Load the warning icon and text
//
hicon = LoadImage(MyDllModuleHandle,
MAKEINTRESOURCE(IDI_WARN),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0
);
if(!LoadString(MyDllModuleHandle,
IDS_DRIVER_NOT_SIGNED,
TempString,
SIZECHARS(TempString))) {
*TempString = TEXT('\0');
}
if ((ndwData->ddData).hFontBold) {
SetWindowFont(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), (ndwData->ddData).hFontBold, TRUE);
}
}
if (hicon) {
hicon = (HICON)SendDlgItemMessage(hwndDlg,
IDC_NDW_PICKDEV_SIGNED_ICON,
STM_SETICON,
(WPARAM)hicon,
0L
);
}
if (hicon) {
DestroyIcon(hicon);
}
SetDlgItemText(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT, TempString);
} else {
//
// Nothing is selected so hide the icon and the text.
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_HIDE);
//
// Disable the OK/Next button, because the user can't select a class driver
// yet.
//
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
}
}
}
}
break;
case NM_RETURN:
case NM_CLICK:
if((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_SIGNED_LINK) {
ShellExecute(hwndDlg,
TEXT("open"),
TEXT("HELPCTR.EXE"),
TEXT("HELPCTR.EXE -url hcp://services/subsite?node=TopLevelBucket_4/Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm"),
NULL,
SW_SHOWNORMAL
);
}
break;
case NM_DBLCLK :
if(((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_DRVLIST) ||
((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_ONEMFG_DRVLIST)) {
if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
goto HandleOK;
} else {
PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
}
}
break;
}
break;
case WM_TIMER :
KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
ndwData->idTimer = 0;
SelectMfgItemNow:
iCur = ListView_GetNextItem((ndwData->ddData).hwndMfgList,
-1,
LVNI_SELECTED
);
if(iCur != -1) {
RECT rcTo, rcFrom;
ListView_EnsureVisible((ndwData->ddData).hwndMfgList, iCur, FALSE);
UpdateWindow((ndwData->ddData).hwndMfgList);
GetWindowRect((ndwData->ddData).hwndDrvList, &rcTo);
MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rcTo, 2);
ListView_GetItemRect((ndwData->ddData).hwndMfgList,
iCur,
&rcFrom,
LVIR_LABEL
);
MapWindowPoints((ndwData->ddData).hwndMfgList,
hwndDlg,
(LPPOINT)&rcFrom,
2
);
DrawAnimatedRects(hwndDlg, IDANI_OPEN, &rcFrom, &rcTo);
LockAndShowListForMfg(&(ndwData->ddData), iCur);
}
break;
case WM_SYSCOLORCHANGE :
_OnSysColorChange(hwndDlg, wParam, lParam);
break;
case WM_HELP: // F1
WinHelp(((LPHELPINFO)lParam)->hItemHandle,
SELECTDEVICE_HELP,
HELP_WM_HELP,
(ndwData->ddData.flags & DD_FLAG_SHOWSIMILARDRIVERS) ?
(ULONG_PTR)SelectDeviceShowSimilarHelpIDs :
(ULONG_PTR)SelectDeviceShowAllHelpIDs
);
break;
case WM_CONTEXTMENU: // right mouse click
WinHelp((HWND)wParam,
SELECTDEVICE_HELP,
HELP_CONTEXTMENU,
(ndwData->ddData.flags & DD_FLAG_SHOWSIMILARDRIVERS) ?
(ULONG_PTR)SelectDeviceShowSimilarHelpIDs :
(ULONG_PTR)SelectDeviceShowAllHelpIDs
);
break;
default :
if (!g_uQueryCancelAutoPlay) {
g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
}
if (uMsg == g_uQueryCancelAutoPlay) {
SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, 1 );
return 1; // cancel auto-play
}
return(FALSE);
}
return TRUE;
}
INT CALLBACK
DriverNodeCompareProc(
LPARAM lParam1,
LPARAM lParam2,
LPARAM lParamSort
)
/*++
Routine Description:
This routine is the callback for the list control sorting that is done when
ListView_SortItems is called.
The sorting this routine does is that if a DriverNode has the
DNF_INF_IS_SIGNED flag then it is considered better than a DriverNode that
does not have this flag. If both DriverNodes have, or don't have, this
flag then a simple string compare is done.
Return Value:
-1 if lParam1 is better than lParam2 (should be higher in the ListControl
+1 if lParam2 is better than lParam1 (should be higher in the ListControl
0 if lParam1 and lParam2 are the same
--*/
{
if ((((PDRIVER_NODE)lParam1)->Flags & DNF_INF_IS_SIGNED) &&
!(((PDRIVER_NODE)lParam2)->Flags & DNF_INF_IS_SIGNED)) {
return -1;
}
if ((((PDRIVER_NODE)lParam2)->Flags & DNF_INF_IS_SIGNED) &&
!(((PDRIVER_NODE)lParam1)->Flags & DNF_INF_IS_SIGNED)) {
return 1;
}
//
// At this point both driver nodes are signed or both are not signed, so
// compare based on their description.
//
return (lstrcmpi(pStringTableStringFromId(((PDEVICE_INFO_SET)lParamSort)->StringTable,
((PDRIVER_NODE)lParam1)->DevDescriptionDisplayName),
pStringTableStringFromId(((PDEVICE_INFO_SET)lParamSort)->StringTable,
((PDRIVER_NODE)lParam2)->DevDescriptionDisplayName)));
}
VOID
_OnSysColorChange(
HWND hWnd,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
This routine notifies all child windows of the specified window when there is
a system color change.
Return Value:
None.
--*/
{
HWND hChildWnd;
hChildWnd = GetWindow(hWnd, GW_CHILD);
while(hChildWnd != NULL) {
SendMessage(hChildWnd, WM_SYSCOLORCHANGE, wParam, lParam);
hChildWnd = GetWindow(hChildWnd, GW_HWNDNEXT);
}
}
DWORD
FillInDeviceList(
IN HWND hwndDlg,
IN PSP_DIALOGDATA lpdd
)
/*++
Routine Description:
This routine sets the dialog to have the appropriate description strings.
It also alternates dialog between showing the manufacturer "double list"
and the single list. This is done by showing/hiding overlapping listview.
NOTE: DO NOT CALL THIS ROUTINE TO WHILE ANOTHER THREAD IS BUSY BUILDING A
CLASS DRIVER LIST. WE WILL HANG HERE UNTIL THE OTHER THREAD COMPLETES!!!!
Arguments:
hwndDlg - Supplies the handle of the dialog window.
lpdd - Supplies the address of a dialog data buffer containing parameters to
be used in filling in the device list.
Return Value:
If success, the return value is NO_ERROR, otherwise, it is an ERROR_* code.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
PDRIVER_NODE DriverNodeHead, CurDriverNode;
DWORD DriverNodeType;
LONG MfgNameId;
INT i;
LPTSTR lpszMfg;
LV_COLUMN lvcCol;
LV_ITEM lviItem;
BOOL bDidDrvList = FALSE;
PDEVINSTALL_PARAM_BLOCK dipb;
DWORD Err = NO_ERROR;
TCHAR szBuf[LINE_LEN];
TCHAR szMessage[MAX_INSTRUCTION_LEN];
TCHAR szText[SDT_MAX_TEXT];
LPTSTR lpszText;
LPGUID ClassGuid;
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return ERROR_INVALID_HANDLE;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
dipb = &(DevInfoElem->InstallParamBlock);
ClassGuid = &(DevInfoElem->ClassGuid);
if(lpdd->bShowCompat) {
DriverNodeHead = DevInfoElem->CompatDriverHead;
DriverNodeType = SPDIT_COMPATDRIVER;
} else {
DriverNodeHead = DevInfoElem->ClassDriverHead;
DriverNodeType = SPDIT_CLASSDRIVER;
}
} else {
//
// We better not be trying to display a compatible driver list if
// we don't have a devinfo element!
//
MYASSERT(!lpdd->bShowCompat);
//
// Since we don't have any compatible drivers to show, we will hide
// the show compatible checkbox.
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
dipb = &(pDeviceInfoSet->InstallParamBlock);
DriverNodeHead = pDeviceInfoSet->ClassDriverHead;
DriverNodeType = SPDIT_CLASSDRIVER;
if(pDeviceInfoSet->HasClassGuid) {
ClassGuid = &(pDeviceInfoSet->ClassGuid);
} else {
//
// Cast away const-ness of this global GUID, since we only use
// LPGUID type (in fact, there is no 'LPCGUID' type defined).
//
ClassGuid = (LPGUID)&GUID_DEVCLASS_UNKNOWN;
}
}
if(!DriverNodeHead) {
if(!(lpdd->flags & DD_FLAG_IS_DIALOGBOX)) {
//
// We can't just go away, so we have to do something useful. For now, simply
// display the UI as if we had a single-Mfg list, except that the list is empty.
//
// Hide the mult mfg controls
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_HIDE);
//
// Show the Single MFG controls
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
//
// Set the Models string
//
lvcCol.mask = LVCF_FMT | LVCF_TEXT;
lvcCol.fmt = LVCFMT_LEFT;
if(USE_CI_SELSTRINGS(dipb)) {
lvcCol.pszText = GET_CI_SELSTRINGS(dipb, ListLabel);
ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
} else {
if(!(LoadString(MyDllModuleHandle,
IDS_NDWSEL_MODELSLABEL,
szBuf,
SIZECHARS(szBuf)))) {
szBuf[0] = TEXT('\0');
}
lvcCol.pszText = szBuf;
ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
}
//
// Use the single listbox view for the driver list.
//
lpdd->hwndDrvList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST);
ListView_DeleteAllItems(lpdd->hwndDrvList);
}
Err = ERROR_DI_BAD_PATH;
goto clean0;
}
if((lpdd->flags & DD_FLAG_IS_DIALOGBOX) && !USE_CI_SELSTRINGS(dipb)) {
//
// If a class installer didn't supply strings for us to use in this dialogbox,
// then retrieve the instruction text to be used.
//
// First, get the class description to use for the dialog text.
//
if(!SetupDiGetClassDescription(ClassGuid, szBuf, SIZECHARS(szBuf), NULL)) {
//
// Fall back to the generic description "device"
//
if(!LoadString(MyDllModuleHandle,
IDS_GENERIC_DEVNAME,
szBuf,
SIZECHARS(szBuf)
)) {
szBuf[0]=TEXT('\0');
}
}
if(!lpdd->bShowCompat) {
//
// Show class list.
//
if(LoadString(MyDllModuleHandle,
IDS_INSTALLSTR1,
szMessage,
SIZECHARS(szMessage))) {
wsprintf(szText, szMessage, szBuf);
} else {
szText[0] = TEXT('\0');
}
} else {
//
// Show compatible list.
//
if(LoadString(MyDllModuleHandle,
IDS_INSTALLSTR0,
szMessage,
SIZECHARS(szMessage))) {
wsprintf(szText, szMessage, szBuf);
} else {
szText[0]=TEXT('\0');
}
lpszText = szText + lstrlen(szText);
if(LoadString(MyDllModuleHandle,
IDS_INSTALLCLASS,
szMessage,
SIZECHARS(szMessage))) {
wsprintf(lpszText, szMessage, szBuf);
} else {
szText[0] = TEXT('\0');
}
}
if(dipb->DriverPath != -1) {
lpszText = szText + lstrlen(szText);
LoadString(MyDllModuleHandle,
IDS_INSTALLOEM1,
lpszText,
SIZECHARS(szText) - lstrlen(szText)
);
} else if (dipb->Flags & DI_SHOWOEM) {
lpszText = szText + lstrlen(szText);
LoadString(MyDllModuleHandle,
IDS_INSTALLOEM,
lpszText,
SIZECHARS(szText) - lstrlen(szText)
);
}
SetDlgItemText(hwndDlg, IDC_NDW_TEXT, szText);
}
if((!lpdd->bShowCompat) && (dipb->Flags & DI_MULTMFGS)) {
//
// Hide the Single MFG controls
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
//
// Show the Multiple MFG controls
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_SHOW);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_SHOW);
//
// Set the colunm heading for the Driver list
//
lvcCol.mask = LVCF_FMT | LVCF_TEXT;
lvcCol.fmt = LVCFMT_LEFT;
if(USE_CI_SELSTRINGS(dipb)) {
lvcCol.pszText = GET_CI_SELSTRINGS(dipb, ListLabel);
ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), 0, &lvcCol);
} else {
if(!(LoadString(MyDllModuleHandle,
IDS_NDWSEL_MODELSLABEL,
szBuf,
SIZECHARS(szBuf)))) {
szBuf[0] = TEXT('\0');
}
lvcCol.pszText = szBuf;
ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), 0, &lvcCol);
}
//
// Use the 2nd listbox of the Manufacturers/Models view for the driver list.
//
lpdd->hwndDrvList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST);
#ifndef ANSI_SETUPAPI
ListView_SetExtendedListViewStyle(lpdd->hwndDrvList, LVS_EX_LABELTIP);
#endif
if (lpdd->hImageList) {
ListView_SetImageList(lpdd->hwndDrvList, lpdd->hImageList, LVSIL_SMALL);
}
//
// No redraw for faster insert
//
SendMessage(lpdd->hwndMfgList, WM_SETREDRAW, FALSE, 0L);
//
// Clean out the MFG list before filling it.
//
ListView_DeleteAllItems(lpdd->hwndMfgList);
lviItem.mask = LVIF_TEXT | LVIF_PARAM;
lviItem.iItem = 0;
lviItem.iSubItem = 0;
//
// Setup the Column Header
//
MfgNameId = -1;
for(CurDriverNode = DriverNodeHead; CurDriverNode; CurDriverNode = CurDriverNode->Next) {
//
// Skip this driver node if it is to be excluded of if it is an old INET driver or
// if it is a BAD driver.
//
if ((CurDriverNode->Flags & DNF_OLD_INET_DRIVER) ||
(CurDriverNode->Flags & DNF_BAD_DRIVER) ||
((CurDriverNode->Flags & DNF_EXCLUDEFROMLIST) &&
!(dipb->FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS))) {
continue;
}
if((MfgNameId == -1) || (MfgNameId != CurDriverNode->MfgName)) {
MfgNameId = CurDriverNode->MfgName;
MYASSERT(CurDriverNode->MfgDisplayName != -1);
lpszMfg = pStringTableStringFromId(pDeviceInfoSet->StringTable,
CurDriverNode->MfgDisplayName
);
lviItem.pszText = lpszMfg;
lviItem.lParam = (LPARAM)CurDriverNode;
i = ListView_InsertItem(lpdd->hwndMfgList, &lviItem);
}
//
// If this driver node is the selected one, preselect here.
//
if(lpdd->iCurDesc == CurDriverNode->DevDescription) {
ListView_SetItemState(lpdd->hwndMfgList,
i,
(LVIS_SELECTED|LVIS_FOCUSED),
(LVIS_SELECTED|LVIS_FOCUSED)
);
ShowListForMfg(lpdd, pDeviceInfoSet, dipb, NULL, i);
bDidDrvList = TRUE;
}
}
//
// Resize the Column
//
ListView_SetColumnWidth(lpdd->hwndMfgList, 0, LVSCW_AUTOSIZE_USEHEADER);
//
// If we did not expand one of the MFGs by default, then
// expand the First MFG.
//
if(!bDidDrvList) {
ListView_SetItemState(lpdd->hwndMfgList,
0,
(LVIS_SELECTED|LVIS_FOCUSED),
(LVIS_SELECTED|LVIS_FOCUSED)
);
ShowListForMfg(lpdd, pDeviceInfoSet, dipb, NULL, 0);
SendMessage(lpdd->hwndMfgList, WM_SETREDRAW, TRUE, 0L);
} else {
//
// We must set redraw back to true before sending the LVM_ENSUREVISIBLE
// message, or otherwise, the listbox item may only be partially exposed.
//
SendMessage(lpdd->hwndMfgList, WM_SETREDRAW, TRUE, 0L);
ListView_EnsureVisible(lpdd->hwndMfgList,
ListView_GetNextItem(lpdd->hwndMfgList, -1, LVNI_SELECTED),
FALSE
);
}
} else {
//
// Hide the mult mfg controls
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
//
// Show the Single MFG controls
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
//
// Set the Models string
//
lvcCol.mask = LVCF_FMT | LVCF_TEXT;
lvcCol.fmt = LVCFMT_LEFT;
if(USE_CI_SELSTRINGS(dipb)) {
lvcCol.pszText = GET_CI_SELSTRINGS(dipb, ListLabel);
ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
} else {
if(!(LoadString(MyDllModuleHandle,
IDS_NDWSEL_MODELSLABEL,
szBuf,
SIZECHARS(szBuf)))) {
szBuf[0] = TEXT('\0');
}
lvcCol.pszText = szBuf;
ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
}
//
// Use the single listbox view for the driver list.
//
lpdd->hwndDrvList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST);
if (lpdd->hImageList) {
ListView_SetImageList(lpdd->hwndDrvList, lpdd->hImageList, LVSIL_SMALL);
}
ShowListForMfg(lpdd, pDeviceInfoSet, dipb, DriverNodeHead, -1);
}
clean0: ; // nothing to do
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do
}
UnlockDeviceInfoSet(pDeviceInfoSet);
return Err;
}
VOID
ShowListForMfg(
IN PSP_DIALOGDATA lpdd,
IN PDEVICE_INFO_SET DeviceInfoSet,
IN PDEVINSTALL_PARAM_BLOCK InstallParamBlock,
IN PDRIVER_NODE DriverNode, OPTIONAL
IN INT iMfg
)
/*++
Routine Description:
This routine builds the driver description list.
THE LOCK MUST ALREADY BE ACQUIRED BEFORE CALLING THIS ROUTINE!
Arguments:
lpdd - Supplies the address of a dialog data buffer containing parameters
to be used in filling in the driver description list.
DeviceInfoSet - Supplies the address of the device information set structure
for which the driver description list is to be built.
InstallParamBlock - Supplies the address of a device installation parameter
block that controls how the list is displayed.
DriverNode - Optionally, supplies a pointer to the first node in a driver node
list to traverse, adding to the list for each node. If DriverNode
is not specified, then the list is to be built based on a particular
manufacturer, whose index in the Manufacturer list is given by iMfg.
iMfg - Supplies the index within the Manufacturer list that the driver
description list is to be based on. This parameter is ignored if a
DriverNode is specified.
Return Value:
None.
--*/
{
INT i;
LV_ITEM lviItem;
LV_FINDINFO lvfiFind;
LONG MfgNameId = -1;
TCHAR szTemp[LINE_LEN];
SYSTEMTIME SystemTime;
TCHAR szDate[LINE_LEN];
TCHAR FormatString[LINE_LEN];
TCHAR VersionString[LINE_LEN]; // Has format a.b.c.d
//
// Set listview sortascending style based on DI_INF_IS_SORTED flag
//
SetWindowLong(lpdd->hwndDrvList,
GWL_STYLE,
(GetWindowLong(lpdd->hwndDrvList, GWL_STYLE) & ~(LVS_SORTASCENDING | LVS_SORTDESCENDING)) |
((InstallParamBlock->Flags & DI_INF_IS_SORTED)
? 0
: LVS_SORTASCENDING)
);
SendMessage(lpdd->hwndDrvList, WM_SETREDRAW, FALSE, 0L);
//
// Clean out the List.
//
ListView_DeleteAllItems(lpdd->hwndDrvList);
if(!DriverNode) {
if (ListView_GetItemCount(lpdd->hwndMfgList) > 0) {
lviItem.mask = LVIF_PARAM;
lviItem.iItem = iMfg;
lviItem.iSubItem = 0;
if(!ListView_GetItem(lpdd->hwndMfgList, &lviItem) ||
!(DriverNode = GetDriverNodeFromLParam(DeviceInfoSet, lpdd, lviItem.lParam))) {
return;
}
MfgNameId = DriverNode->MfgName;
} else {
//
// This means that there are no Manufacturers so we just have a empty list.
//
return;
}
}
lviItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lviItem.iItem = 0;
lviItem.iSubItem = 0;
//
// Add descriptions to the list
//
for( ; DriverNode; DriverNode = DriverNode->Next) {
if((MfgNameId != -1) && (MfgNameId != DriverNode->MfgName)) {
//
// We've gone beyond the manufacturer list--break out of loop.
//
break;
}
//
// If this is a special "Don't show me" one, then skip it
//
if ((DriverNode->Flags & DNF_OLD_INET_DRIVER) ||
(DriverNode->Flags & DNF_BAD_DRIVER) ||
((DriverNode->Flags & DNF_EXCLUDEFROMLIST) &&
!(InstallParamBlock->FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS))) {
continue;
}
if(DriverNode->Flags & DNF_DUPDESC) {
lstrcpy(szTemp,
pStringTableStringFromId(DeviceInfoSet->StringTable,
DriverNode->DevDescriptionDisplayName)
);
//
//For drivers with duplicate descriptions add the provider name
//in parens.
//
#ifdef UNICODE
if (GetWindowLong(lpdd->hwndDrvList, GWL_EXSTYLE) & WS_EX_RTLREADING) {
lstrcat(szTemp, TEXT("\x200E"));
}
#endif
lstrcat(szTemp, pszSpaceLparen);
if(DriverNode->ProviderDisplayName != -1) {
lstrcat(szTemp,
pStringTableStringFromId(DeviceInfoSet->StringTable,
DriverNode->ProviderDisplayName)
);
}
lstrcat(szTemp, pszRparen);
#ifdef UNICODE
if (GetWindowLong(lpdd->hwndDrvList, GWL_EXSTYLE) & WS_EX_RTLREADING) {
lstrcat(szTemp, TEXT("\x200E"));
}
#endif
} else if (DriverNode->Flags & DNF_DUPPROVIDER) {
lstrcpy(szTemp,
pStringTableStringFromId(DeviceInfoSet->StringTable,
DriverNode->DevDescriptionDisplayName)
);
//
//For drivers with duplicate descriptions and providers, add the
//driver version and driver date if there is one, in brackets.
//
if (DriverNode->DriverVersion != 0) {
ULARGE_INTEGER Version;
Version.QuadPart = DriverNode->DriverVersion;
if(!LoadString(MyDllModuleHandle, IDS_VERSION, FormatString, SIZECHARS(FormatString))) {
FormatString[0]=TEXT('\0');
}
wsprintf(VersionString, FormatString,
HIWORD(Version.HighPart), LOWORD(Version.HighPart),
HIWORD(Version.LowPart), LOWORD(Version.LowPart));
lstrcat(szTemp, VersionString);
}
if ((DriverNode->DriverDate.dwLowDateTime != 0) ||
(DriverNode->DriverDate.dwHighDateTime != 0)) {
if (FileTimeToSystemTime(&(DriverNode->DriverDate), &SystemTime)) {
if (GetDateFormat(LOCALE_USER_DEFAULT,
DATE_SHORTDATE,
&SystemTime,
NULL,
FormatString,
SIZECHARS(FormatString)
) != 0) {
#ifdef UNICODE
if (GetWindowLong(lpdd->hwndDrvList, GWL_EXSTYLE) & WS_EX_RTLREADING) {
wsprintf(szDate, TEXT(" \x200E[%s]\x200E"), FormatString);
} else {
wsprintf(szDate, TEXT(" [%s]"), FormatString);
}
#else
wsprintf(szDate, TEXT(" [%s]"), FormatString);
#endif
lstrcat(szTemp, szDate);
}
}
}
} else {
lstrcpy(szTemp,
pStringTableStringFromId(DeviceInfoSet->StringTable,
DriverNode->DevDescriptionDisplayName));
}
lviItem.pszText = szTemp;
lviItem.lParam = (LPARAM)DriverNode;
lviItem.iImage = (DriverNode->Flags & DNF_INF_IS_SIGNED) ?
IMAGE_ICON_SIGNED :
IMAGE_ICON_NOT_SIGNED;
if(ListView_InsertItem(lpdd->hwndDrvList, &lviItem) != -1) {
lviItem.iItem++;
}
}
//
// Sort the list unless the DI_INF_IS_SORTED flag is set
//
if (GetWindowLong(lpdd->hwndDrvList, GWL_STYLE) & LVS_SORTASCENDING) {
ListView_SortItems(lpdd->hwndDrvList,
(PFNLVCOMPARE)DriverNodeCompareProc,
(LPARAM)DeviceInfoSet
);
}
//
// Resize the Column
//
ListView_SetColumnWidth(lpdd->hwndDrvList, 0, LVSCW_AUTOSIZE_USEHEADER);
//
// select the current description string
//
if(lpdd->iCurDesc == -1) {
i = 0;
} else {
lvfiFind.flags = LVFI_STRING;
lvfiFind.psz = pStringTableStringFromId(DeviceInfoSet->StringTable,
lpdd->iCurDesc
);
i = ListView_FindItem(lpdd->hwndDrvList, -1, &lvfiFind);
if(i == -1) {
i = 0;
}
}
ListView_SetItemState(lpdd->hwndDrvList,
i,
(LVIS_SELECTED|LVIS_FOCUSED),
(LVIS_SELECTED|LVIS_FOCUSED)
);
//
// We must turn redraw back on before sending the LVM_ENSUREVISIBLE message, or
// otherwise the item may only be partially visible.
//
SendMessage(lpdd->hwndDrvList, WM_SETREDRAW, TRUE, 0L);
ListView_EnsureVisible(lpdd->hwndDrvList, i, FALSE);
}
VOID
LockAndShowListForMfg(
IN PSP_DIALOGDATA lpdd,
IN INT iMfg
)
/*++
Routine Description:
This routine is a wrapper for ShowListForMfg. It is to be called from points
where the device information set lock is not already owned (e.g., the dialog
prop message loop.
Arguments:
lpdd - Supplies the address of a dialog data buffer containing parameters
to be used in filling in the driver description list.
iMfg - Supplies the index within the Manufacturer list that the driver
description list is to be based on.
Return Value:
None.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINSTALL_PARAM_BLOCK dipb;
PDEVINFO_ELEM DevInfoElem;
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
dipb = DevInfoElem ? &(DevInfoElem->InstallParamBlock)
: &(pDeviceInfoSet->InstallParamBlock);
ShowListForMfg(lpdd,
pDeviceInfoSet,
dipb,
NULL,
iMfg
);
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do
}
UnlockDeviceInfoSet(pDeviceInfoSet);
}
BOOL
InitSelectDeviceDlg(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
)
/*++
Routine Description:
This routine initializes the select device wizard page. It
builds the class list if it is needed, shows/hides necessary
controls based on Flags, and comes up with the right text
description of what's going on.
Arguments:
hwndDlg - Handle to dialog window
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
Return Value:
TRUE if we have at least one driver (compat or class) displayed.
FALSE if we do not have any drivers (class and compat) displayed.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
PDEVINSTALL_PARAM_BLOCK dipb;
SP_DEVINFO_DATA DevInfoData;
SP_DEVINSTALL_PARAMS DeviceInstallParams;
DWORD DriverType = SPDIT_CLASSDRIVER;
DWORD Err;
INT ShowWhat;
LPGUID ClassGuid;
HICON hicon = NULL;
LV_COLUMN lvcCol;
BOOL SpawnClassDriverSearch = FALSE;
PCLASSDRV_THREAD_CONTEXT ClassDrvThreadContext;
HCURSOR hOldCursor;
BOOL Return = TRUE;
PSP_DIALOGDATA lpdd;
HICON hIcon;
TCHAR szBuf[LINE_LEN];
HFONT hfont;
LOGFONT LogFont;
MYASSERT(ndwData);
lpdd = &(ndwData->ddData);
MYASSERT(lpdd);
if(!lpdd->hwndMfgList) {
UINT ImageListFlags = 0;
//
// Then this is the first time we've initialized this dialog (we may hit
// this routine multiple times in the wizard case, because the user can
// go back and forth between pages).
//
lpdd->hwndMfgList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST);
//
// Don't worry--hwndDrvList will be set later in FillInDeviceList().
//
//
// Create an image list and add the signed and not signed (blank) icons
// to the list.
// Note: If the window is in RTL then we need to OR in the ILC_MIRROR flag
// so that the icons do NOT get mirrored along with the rest of the UI.
// This doesn't really make any sense that you have to or in a ILC_MIRROR
// flag so the icons do NOT get mirrored, but that is the way it works.
//
ImageListFlags = ILC_MASK;
#ifdef UNICODE
if (GetWindowLong(hwndDlg, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) {
ImageListFlags |= ILC_MIRROR;
}
#endif
lpdd->hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
ImageListFlags,
1,
1
);
if (lpdd->hImageList) {
ImageList_SetBkColor(lpdd->hImageList, GetSysColor(COLOR_WINDOW));
if ((hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(IDI_BLANK))) != NULL) {
ImageList_AddIcon(lpdd->hImageList, hIcon);
DestroyIcon(hIcon);
}
if ((hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(IDI_SIGNED))) != NULL) {
ImageList_AddIcon(lpdd->hImageList, hIcon);
DestroyIcon(hIcon);
}
}
//
// Create the normal and bold fonts for the digital signing text.
//
lpdd->hFontNormal = lpdd->hFontBold = NULL;
if ((hfont = (HFONT)SendMessage(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), WM_GETFONT, 0, 0)) != NULL) {
GetObject(hfont, sizeof(LogFont), &LogFont);
lpdd->hFontNormal = CreateFontIndirect(&LogFont);
}
if ((hfont = (HFONT)SendMessage(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), WM_GETFONT, 0, 0)) != NULL) {
GetObject(hfont, sizeof(LogFont), &LogFont);
LogFont.lfWeight = FW_BOLD;
lpdd->hFontBold = CreateFontIndirect(&LogFont);
}
#ifndef ANSI_SETUPAPI
ListView_SetExtendedListViewStyle(lpdd->hwndMfgList, LVS_EX_LABELTIP);
#endif
//
// Insert a ListView column for each of the listboxes.
// Set the text for the Manufacturer label now since it can't be changed
// by class installers like the model label can.
//
lvcCol.mask = 0;
ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), 0, &lvcCol);
ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
lvcCol.mask = LVCF_FMT | LVCF_TEXT;
lvcCol.fmt = LVCFMT_LEFT;
if(!(LoadString(MyDllModuleHandle,
IDS_NDWSEL_MFGLABEL,
szBuf,
SIZECHARS(szBuf)))) {
szBuf[0] = TEXT('\0');
}
lvcCol.pszText = szBuf;
ListView_InsertColumn(lpdd->hwndMfgList, 0, &lvcCol);
}
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return FALSE;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
dipb = &(DevInfoElem->InstallParamBlock);
ClassGuid = &(DevInfoElem->ClassGuid);
//
// Fill in a SP_DEVINFO_DATA structure for a later call to
// SetupDiBuildDriverInfoList.
//
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
&DevInfoData
);
//
// Set flags indicating which driver lists already exist.
//
if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDCOMPATINFO) {
lpdd->bKeeplpCompatDrvList = TRUE;
}
if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) {
lpdd->bKeeplpClassDrvList = TRUE;
}
if(DevInfoElem->SelectedDriver) {
lpdd->bKeeplpSelectedDrv = TRUE;
}
//
// We want to start out with the compatible driver list.
//
DriverType = SPDIT_COMPATDRIVER;
} else {
dipb = &(pDeviceInfoSet->InstallParamBlock);
if(pDeviceInfoSet->HasClassGuid) {
ClassGuid = &(pDeviceInfoSet->ClassGuid);
} else {
//
// Cast away const-ness of this global GUID, since we only use
// LPGUID type (in fact, there is no 'LPCGUID' type defined).
//
ClassGuid = (LPGUID)&GUID_DEVCLASS_UNKNOWN;
}
if(pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) {
lpdd->bKeeplpClassDrvList = TRUE;
}
if(pDeviceInfoSet->SelectedClassDriver) {
lpdd->bKeeplpSelectedDrv = TRUE;
}
}
//
// Get/set class icon
//
if (IsEqualGUID(ClassGuid, &GUID_NULL)) {
if (!SetupDiLoadClassIcon(&GUID_DEVCLASS_UNKNOWN, &hicon, &(lpdd->iBitmap))) {
hicon = NULL;
}
} else {
if (!SetupDiLoadClassIcon(ClassGuid, &hicon, &(lpdd->iBitmap))) {
hicon = NULL;
}
}
if (hicon) {
SendDlgItemMessage(hwndDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hicon, 0L);
}
//
// If we are supposed to override the instructions and title with the class
// installer-provided strings, do it now.
//
if(USE_CI_SELSTRINGS(dipb)) {
if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
SetWindowText(hwndDlg, GET_CI_SELSTRINGS(dipb, Title));
} else {
#ifndef ANSI_SETUPAPI
// Set wizard title and subtitle
//
PropSheet_SetHeaderTitle(GetParent(hwndDlg),
PropSheet_HwndToIndex(GetParent(hwndDlg), hwndDlg),
GET_CI_SELSTRINGS(dipb, Title));
PropSheet_SetHeaderSubTitle(GetParent(hwndDlg),
PropSheet_HwndToIndex(GetParent(hwndDlg), hwndDlg),
GET_CI_SELSTRINGS(dipb, SubTitle));
#endif
}
SetDlgItemText(hwndDlg, IDC_NDW_TEXT, GET_CI_SELSTRINGS(dipb, Instructions));
}
//
// If we should not allow OEM driver, then hide the HAVE disk button.
//
if(!(dipb->Flags & DI_SHOWOEM)) {
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_HAVEDISK), SW_HIDE);
}
#ifdef UNICODE
//
// Hide the Windows Update button if we should not search the web.
//
if ((!(dipb->FlagsEx & DI_FLAGSEX_SHOWWINDOWSUPDATE)) ||
(CDMIsInternetAvailable() == FALSE)) {
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_WINDOWSUPDATE), SW_HIDE);
}
#else
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_WINDOWSUPDATE), SW_HIDE);
#endif
if (dipb->FlagsEx & DI_FLAGSEX_FILTERSIMILARDRIVERS) {
lpdd->flags |= DD_FLAG_SHOWSIMILARDRIVERS;
}
//
// In order to decrease the amount of time the user must wait before they're able
// to work with the Select Device dialog, we have adopted a 'hybrid' multi-threaded
// approach. As soon as we get the first displayable list built, then we will return,
// and build the other list (if necessary) in another thread.
//
// We do it this way because it's easier, it maintains the existing external behavior,
// and because it's easier.
//
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); // Potentially slow operations ahead!
if(DriverType == SPDIT_COMPATDRIVER) {
//
// OR in the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag so that we don't include
// old internet drivers in the list that we get back.
//
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if (SetupDiGetDeviceInstallParams(lpdd->DevInfoSet,
&DevInfoData,
&DeviceInstallParams
))
{
DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
SetupDiSetDeviceInstallParams(lpdd->DevInfoSet,
&DevInfoData,
&DeviceInstallParams
);
}
SetupDiBuildDriverInfoList(lpdd->DevInfoSet,
&DevInfoData,
SPDIT_COMPATDRIVER
);
//
// Verify that there are some devices in the list to show.
//
if(bNoDevsToShow(DevInfoElem)) {
if(!lpdd->bKeeplpCompatDrvList) {
SetupDiDestroyDriverInfoList(lpdd->DevInfoSet, &DevInfoData, SPDIT_COMPATDRIVER);
}
DriverType = SPDIT_CLASSDRIVER;
} else if(!lpdd->bKeeplpClassDrvList) {
//
// We have a list to get our UI up and running, but we don't have a class driver
// list yet. Set a flag that causes us to spawn a thread for this later.
//
SpawnClassDriverSearch = TRUE;
}
}
if(DriverType == SPDIT_CLASSDRIVER) {
//
// We couldn't find any compatible drivers, so we fall back on the class driver
// list. In this case we have to have this list before continuing. In the
// future, maybe we'll get fancier and do this in a separate thread, but for now,
// we just make the user wait.
//
//
// OR in the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag so that we don't include
// old internet drivers in the list that we get back.
//
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if (SetupDiGetDeviceInstallParams(lpdd->DevInfoSet,
DevInfoElem ? &DevInfoData : NULL,
&DeviceInstallParams
))
{
DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
SetupDiSetDeviceInstallParams(lpdd->DevInfoSet,
DevInfoElem ? &DevInfoData : NULL,
&DeviceInstallParams
);
}
SetupDiBuildDriverInfoList(lpdd->DevInfoSet,
DevInfoElem ? &DevInfoData : NULL,
SPDIT_CLASSDRIVER
);
}
SetCursor(LoadCursor(NULL, IDC_ARROW)); // Done with slow operations.
if(DriverType == SPDIT_COMPATDRIVER) {
//
// Since we ran this through bNoDevsToShow() above, and it succeeded, we know
// there's at least one driver in the compatible driver list.
//
// (NOTE: We don't call the class installer with a DIF_SELECTBESTCOMPATDRV
// here. The assumption is that any class installer that wants to get in
// the act should check for the DI_FLAGSEX_AUTOSELECTRANK0, and try to select
// a driver _before_ going ahead and letting the default behavior of
// SetupDiSelectDevice occur.)
//
if((dipb->FlagsEx & DI_FLAGSEX_AUTOSELECTRANK0) &&
!(DevInfoElem->CompatDriverHead->Rank)) {
if(!SetupDiSelectBestCompatDrv(lpdd->DevInfoSet, &DevInfoData)) {
//
// The only time this failure should happen is if the device is
// a member of a set with an associated class, and the best driver
// match we found is from an INF of a different class.
//
if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
EndDialog(hwndDlg, GetLastError());
goto clean0;
}
}
//
// No need to spawn a class driver search thread.
//
SpawnClassDriverSearch = FALSE;
EndDialog(hwndDlg, NO_ERROR);
goto clean0;
}
lpdd->bShowCompat = TRUE;
CheckDlgButton(hwndDlg,
IDC_NDW_PICKDEV_COMPAT,
BST_CHECKED
);
} else {
//
// There is no compatible list, so hide the radio buttons.
//
lpdd->bShowCompat = FALSE;
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
}
//
// Initial current description. This will be used to set
// the Default ListView selection.
//
if(lpdd->iCurDesc == -1) {
//
// If we already have a selected driver for the devinfo set or element,
// then we'll use that, otherwise, we'll use the devinfo element's
// description (if applicable).
//
if(DevInfoElem) {
if(DevInfoElem->SelectedDriver) {
lpdd->iCurDesc = DevInfoElem->SelectedDriver->DevDescription;
} else {
TCHAR TempString[LINE_LEN];
ULONG TempStringSize;
//
// Use the caller-supplied device description, if there is one.
// If not, then see if we can retrieve the DeviceDesc registry
// property.
//
TempStringSize = sizeof(TempString);
if((DevInfoElem->DeviceDescription == -1) &&
(CM_Get_DevInst_Registry_Property(DevInfoElem->DevInst,
CM_DRP_DEVICEDESC,
NULL,
TempString,
&TempStringSize,
0) == CR_SUCCESS)) {
//
// We were able to retrieve a device description. Now store it
// (case-insensitive only) in the devinfo element.
//
DevInfoElem->DeviceDescription = pStringTableAddString(
pDeviceInfoSet->StringTable,
TempString,
STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
NULL,0
);
}
lpdd->iCurDesc = DevInfoElem->DeviceDescription;
}
} else {
if(pDeviceInfoSet->SelectedClassDriver) {
lpdd->iCurDesc = pDeviceInfoSet->SelectedClassDriver->DevDescription;
}
}
}
Err = FillInDeviceList(hwndDlg, lpdd);
if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
HWND hLineWnd;
RECT Rect;
//
// If FillInDeviceList() fails during init time, don't even bring up the dialog.
//
if(Err != NO_ERROR) {
EndDialog(hwndDlg, Err);
goto clean0;
}
//
// Set the initial focus on the OK button.
//
SetFocus(GetDlgItem(hwndDlg, IDOK));
//
// Use the fancy etched frame style for the separator bar in the dialog.
//
hLineWnd = GetDlgItem(hwndDlg, IDD_DEVINSLINE);
SetWindowLong(hLineWnd,
GWL_EXSTYLE,
(GetWindowLong(hLineWnd, GWL_EXSTYLE) | WS_EX_STATICEDGE)
);
GetClientRect(hLineWnd, &Rect);
SetWindowPos(hLineWnd,
HWND_TOP,
0,
0,
Rect.right,
GetSystemMetrics(SM_CYEDGE),
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED
);
}
//
// If DriverType is SPDIT_CLASSDRIVER and ListView_GetItemCount returns 0 then
// we don't have any items to show at all. This will only happen when we search
// the default Windows INF directory and we do not have any INFs for a device.
//
if ((DriverType == SPDIT_CLASSDRIVER) &&
(0 == ListView_GetItemCount(lpdd->hwndDrvList))) {
TCHAR TempString[LINE_LEN];
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_SHOW);
if(!LoadString(MyDllModuleHandle, IDS_NDW_NO_DRIVERS, TempString, SIZECHARS(TempString))) {
TempString[0]=TEXT('\0');
}
SetDlgItemText(hwndDlg, IDC_NDW_STATUS_TEXT, TempString);
if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
} else {
if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
}
}
Return = FALSE;
}
clean0: ; // nothing to do
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// If we're doing the dialog box version, then an exception should cause us to
// terminate the dialog and return an error. Note that presently, the dialog
// case is the only time we'll try to spawn off a driver search thread, so we're
// safe in resetting that flag here as well.
//
if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
EndDialog(hwndDlg, ERROR_INVALID_DATA);
SpawnClassDriverSearch = FALSE;
}
}
UnlockDeviceInfoSet(pDeviceInfoSet);
if(SpawnClassDriverSearch) {
//
// Allocate a context structure to pass to the auxilliary thread (the auxilliary
// thread will take care of freeing the memory).
//
if(!(ClassDrvThreadContext = MyMalloc(sizeof(CLASSDRV_THREAD_CONTEXT)))) {
EndDialog(hwndDlg, ERROR_NOT_ENOUGH_MEMORY);
} else {
//
// Fill in the context structure, and fire off the thread. NOTE: The DevInfoData
// struct has to have been filled in above for us to have gotten to this point.
//
ClassDrvThreadContext->DeviceInfoSet = lpdd->DevInfoSet;
CopyMemory(&(ClassDrvThreadContext->DeviceInfoData),
&DevInfoData,
sizeof(DevInfoData)
);
ClassDrvThreadContext->NotificationWindow = hwndDlg;
if(_beginthread(ClassDriverSearchThread, 0, ClassDrvThreadContext) == -1) {
//
// Assume out-of-memory
//
MyFree(ClassDrvThreadContext);
EndDialog(hwndDlg, ERROR_NOT_ENOUGH_MEMORY);
} else {
lpdd->AuxThreadRunning = TRUE;
}
}
}
return Return;
}
PDRIVER_NODE
GetDriverNodeFromLParam(
IN PDEVICE_INFO_SET DeviceInfoSet,
IN PSP_DIALOGDATA lpdd,
IN LPARAM lParam
)
/*++
Routine Description:
This routine interprets lParam as a pointer to a driver node, and tries to
find the node in the class driver list for either the selected devinfo element,
or the set itself. If the lpdd flags field has the DD_FLAG_USE_DEVINFO_ELEM bit
set, then the lpdd's DevInfoElem will be used instead of the currently selected
device.
Arguments:
DeviceInfoSet - Supplies the address of the device information set structure
to search for the driver node in.
lpdd - Supplies the address of a dialog data structure that specifies whether
the wizard has an explicit association to the global class driver list or
to a particular device information element, and if so, what it's associated
with.
lParam - Supplies a value which may be the address of a driver node. The
appropriate linked list of driver nodes is searched to see if one of them
has this value as its address, and if so, a pointer to that driver node is
returned.
Return Value:
If success, the return value is the address of the matching driver node, otherwise,
it is NULL.
--*/
{
PDRIVER_NODE CurDriverNode;
PDEVINFO_ELEM DevInfoElem;
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = DeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
CurDriverNode = (lpdd->bShowCompat) ? DevInfoElem->CompatDriverHead
: DevInfoElem->ClassDriverHead;
} else {
MYASSERT(!lpdd->bShowCompat);
CurDriverNode = DeviceInfoSet->ClassDriverHead;
}
while(CurDriverNode) {
if(CurDriverNode == (PDRIVER_NODE)lParam) {
return CurDriverNode;
} else {
CurDriverNode = CurDriverNode->Next;
}
}
return NULL;
}
BOOL
OnSetActive(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
)
/*++
Routine Description:
This routine handles the PSN_SETACTIVE message of the select device wizard
page.
Arguments:
hwndDlg - Supplies the window handle of the wizard dialog page.
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
Return Value:
If success, the return value is TRUE, otherwise, it is FALSE.
--*/
{
BOOL b = TRUE;
PSP_INSTALLWIZARD_DATA iwd;
PSP_DIALOGDATA lpdd;
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
PDEVINSTALL_PARAM_BLOCK dipb;
MYASSERT(ndwData);
iwd = &(ndwData->InstallData);
lpdd = &(ndwData->ddData);
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return FALSE;
}
//
// Make sure our "waiting for class list" static text control is hidden!
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
dipb = &(DevInfoElem->InstallParamBlock);
} else {
dipb = &(pDeviceInfoSet->InstallParamBlock);
}
//
// Set the Button State
//
if((iwd->Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
(iwd->Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
!(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
//
// No back if we skipped the Class list, and are in express mode
//
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
} else {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
}
//
// Set the New Class install params.
// If we are being jumped to by a dyna wiz page,
// then do not call the class installer
//
if(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED) {
InitSelectDeviceDlg(hwndDlg, ndwData);
} else {
BOOL FlagNeedsReset = FALSE;
SP_DEVINFO_DATA DeviceInfoData;
DWORD CiErr;
PDEVINFO_ELEM CurDevInfoElem;
//
// Call the Class Installer
//
if(!(dipb->Flags & DI_NODI_DEFAULTACTION)) {
dipb->Flags |= DI_NODI_DEFAULTACTION;
FlagNeedsReset = TRUE;
}
if(DevInfoElem) {
//
// Initialize a SP_DEVINFO_DATA buffer to use as an argument to
// SetupDiCallClassInstaller.
//
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
&DeviceInfoData
);
}
//
// We need to unlock the HDEVINFO before calling the class installer.
//
UnlockDeviceInfoSet(pDeviceInfoSet);
pDeviceInfoSet = NULL;
if(_SetupDiCallClassInstaller(DIF_SELECTDEVICE,
lpdd->DevInfoSet,
DevInfoElem ? &DeviceInfoData : NULL,
CALLCI_LOAD_HELPERS | CALLCI_CALL_HELPERS)) {
CiErr = NO_ERROR;
} else {
CiErr = GetLastError();
}
//
// Re-acquire the HDEVINFO lock.
//
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return FALSE;
}
if(DevInfoElem && !(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM)) {
//
// Verify that the class installer didn't do something nasty like delete
// the currently selected devinfo element!
//
for(CurDevInfoElem = pDeviceInfoSet->DeviceInfoHead;
CurDevInfoElem;
CurDevInfoElem = CurDevInfoElem->Next) {
if(CurDevInfoElem = DevInfoElem) {
break;
}
}
if(!CurDevInfoElem) {
//
// The class installer deleted the selected devinfo element. Get
// the newly-selected one, or fall back to the global driver list
// if none selected.
//
if(DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem) {
dipb = &(DevInfoElem->InstallParamBlock);
} else {
dipb = &(pDeviceInfoSet->InstallParamBlock);
}
//
// Don't need to reset the default action flag.
//
FlagNeedsReset = FALSE;
}
}
//
// Reset the DI_NODI_DEFAULTACTION flag if necessary.
//
if(FlagNeedsReset) {
dipb->Flags &= ~DI_NODI_DEFAULTACTION;
}
switch(CiErr) {
//
// Class installer did the select, so goto analyze
//
case NO_ERROR :
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_DYNAWIZ_ANALYZEDEV_PAGE);
break;
//
// Class installer wants us to do default.
//
case ERROR_DI_DO_DEFAULT :
InitSelectDeviceDlg(hwndDlg, ndwData);
break;
default :
//
// If we are doing an OEM select, and we fail, then
// we should init after clearing the OEM stuff.
//
if(iwd->Flags & NDW_INSTALLFLAG_CI_PICKED_OEM) {
iwd->Flags &= ~NDW_INSTALLFLAG_CI_PICKED_OEM;
//
// Destroy the existing class driver list.
//
if(DevInfoElem) {
//
// Initialize a SP_DEVINFO_DATA buffer to use as an argument to
// SetupDiDestroyDriverInfoList.
//
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
&DeviceInfoData
);
}
SetupDiDestroyDriverInfoList(lpdd->DevInfoSet,
DevInfoElem ? &DeviceInfoData : NULL,
SPDIT_CLASSDRIVER
);
//
// Make sure the OEM button is shown.
//
dipb->Flags |= DI_SHOWOEM;
InitSelectDeviceDlg(hwndDlg, ndwData);
} else {
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_DYNAWIZ_SELECTCLASS_PAGE);
}
break;
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
//
// Reference the following variable so that the compiler will respect ordering w.r.t.
// assignment.
//
pDeviceInfoSet = pDeviceInfoSet;
}
if(pDeviceInfoSet) {
UnlockDeviceInfoSet(pDeviceInfoSet);
}
return b;
}
BOOL
pSetupIsSelectedHardwareIdValid(
IN HWND hWnd,
IN PSP_DIALOGDATA lpdd,
IN INT iCur
)
/*++
Routine Description:
This routine will check to see if the driver selected by the user is valid. If the
driver is not valid then we will prompt the user with a message box telling them that
the driver was not writen for their hardware and ask them if they want to continue.
A compatible driver is considered valid if one of the Hardware or Compatible IDs of
the driver node matches a Hardware or Compatible ID of the hardware. The only reason
we have this check is that class/co-installers can do the list themselves so we just
need to make sure they didn't stick a driver node into the compatible list that is not
really compatible.
A class driver is considered valid if it has the same Name, section name, and INF as a
driver in the compatible list. Or if one of the Hardware or Compatible IDs of the
driver node matches a Hardware or Compatible ID of the hardware.
Arguments:
hwnd - Supplies the window handle of the wizard dialog page.
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
iCur - The index of the selected driver in the list view.
Return Value:
TRUE if the selected driver is valid, or if the selected driver is NOT valid but the
user said they still want to install it.
FALSE with GetLastError() == NO_ERROR if the selected driver is NOT valid
and the user does NOT want to install it.
return FALSE on errors with GetLastError() set apropriately
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDRIVER_NODE DriverNode;
LV_ITEM lviItem;
PDEVINFO_ELEM DevInfoElem;
LPTSTR Title = NULL;
LPTSTR Message = NULL;
UINT MessageLen;
BOOL bRet = FALSE;
LPTSTR IDBuffer = NULL;
ULONG IDBufferLen;
PTSTR pID, SelectedDriverHardwareId, SelectedDriverCompatibleId;
DWORD i, j;
int FailCount = 0;
PTSTR StringBuffers = NULL;
DWORD Err = ERROR_INVALID_DATA;
//
// If the DD_FLAG_USE_DEVINFO_ELEM flag is not set then this device did not have
// we don't have a DevNode to validate the choosen ID against...so just return
// TRUE.
//
MYASSERT(lpdd);
if (!(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM))
return TRUE;
if (!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return FALSE;
}
//
// allocate memory required for various strings
// to reduce stack usage
//
StringBuffers = (PTSTR)MyMalloc(sizeof(TCHAR)*(LINE_LEN+SDT_MAX_TEXT+REGSTR_VAL_MAX_HCID_LEN));
if(!StringBuffers) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
Title = StringBuffers; // [LINE_LEN]
Message = Title+LINE_LEN; // [SDT_MAX_TEXT]
IDBuffer = Message+SDT_MAX_TEXT; // [REGSTR_VAL_MAX_HCID_LEN]
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
//
// We won't verify the selected driver for certain classes of devices. This is
// usually because the device is not very Plug and Play and so we can't tell
// what is a valid driver and what isn't a valid driver. Currently the
// list of classes that we don't verify are:
//
// Monitor
//
if (DevInfoElem &&
(IsEqualGUID(&GUID_DEVCLASS_MONITOR, &(DevInfoElem->ClassGuid)))) {
bRet = TRUE;
goto clean0;
}
lviItem.mask = LVIF_PARAM;
lviItem.iItem = iCur;
lviItem.iSubItem = 0;
if(ListView_GetItem(lpdd->hwndDrvList, &lviItem)) {
DriverNode = GetDriverNodeFromLParam(pDeviceInfoSet, lpdd, lviItem.lParam);
} else {
DriverNode = NULL;
}
if (DriverNode) {
//
//Retrieve the HardwareId for the selected driver.
//
SelectedDriverHardwareId = pStringTableStringFromId(pDeviceInfoSet->StringTable,
DriverNode->HardwareId
);
for (i=0; !bRet, i<2; i++) {
IDBufferLen = REGSTR_VAL_MAX_HCID_LEN;
if (CM_Get_DevInst_Registry_Property_Ex(
DevInfoElem->DevInst,
(i ? CM_DRP_COMPATIBLEIDS : CM_DRP_HARDWAREID),
NULL,
IDBuffer,
&IDBufferLen,
0,
pDeviceInfoSet->hMachine) == CR_SUCCESS) {
//
//See if the HardwareID for the selected driver matches any of the
//Hardware or Compatible IDs for the actual hardware.
//
for (pID = IDBuffer; !bRet, *pID; pID += (lstrlen(pID) + 1)) {
if (lstrcmpi(SelectedDriverHardwareId, pID) == 0) {
bRet = TRUE;
break;
}
}
//
//See if any of the Compatible IDs for the selceted driver matches any
//of the Hardware or Compatible IDs for the actual hardware
//
for (j=0; !bRet, j<DriverNode->NumCompatIds; j++) {
SelectedDriverCompatibleId = pStringTableStringFromId(
pDeviceInfoSet->StringTable,
DriverNode->CompatIdList[j]);
for (pID = IDBuffer; !bRet, *pID; pID += (lstrlen(pID) + 1)) {
if (lstrcmpi(SelectedDriverCompatibleId, pID) == 0) {
bRet = TRUE;
break;
}
}
}
} else {
FailCount++;
}
}
//
//If FailCount is 2 then CM_Get_DevInst_Registry_Property_Ex failed for both
//CM_DRP_HARDWAREID and CM_DRP_COMPATIBLEIDS. Since this DevNode does not
//have any Hardware or Compatible IDs we will let the user install any
//driver they want on this device. This usually happens only with manually
//installed devices.
//
if (FailCount == 2) {
bRet = TRUE;
}
//
// If bRet is FALSE at this point the none of the Hardware or Compatible Ids of
// the selected driver node match any of the Hardware or Compatible Ids of the
// actuall hardware. We will do one last check here if this is a class driver.
// We will see if this class driver node has the same description, install section,
// and INF as a driver in the compatible list. The reason for this is that we don't
// handle duplicate descriptions well for class drivers since we don't compute their
// Rank. This means that if two driver nodes exist in an INF with the same description
// we might not have the correct matching one in the class list.
//
if (!bRet && (!lpdd->bShowCompat)) {
PDRIVER_NODE CurDriverNode = NULL;
if (DevInfoElem) {
//
// Enumerate through all of the compatible driver nodes
//
for(CurDriverNode = DevInfoElem->CompatDriverHead;
CurDriverNode;
CurDriverNode = CurDriverNode->Next) {
if ((CurDriverNode->InfFileName == DriverNode->InfFileName) &&
(CurDriverNode->InfSectionName == DriverNode->InfSectionName) &&
(CurDriverNode->DrvDescription == DriverNode->DrvDescription)) {
//
// We found a node that matches ours in the compatible driver list so
// that means that this class dirver node is good.
//
bRet = TRUE;
break;
}
}
}
}
//
//The ID of the driver that the user selected does not match any of the Hardware or
//Compatible IDs of this device. Warn the user that this is a bad thing and see if they
//want to continue.
//
if (!bRet) {
if(!LoadString(MyDllModuleHandle, IDS_DRIVER_UPDATE_TITLE, Title, LINE_LEN)) {
Title[0]=TEXT('\0');
}
MessageLen = LoadString(MyDllModuleHandle, IDS_DRIVER_NOMATCH1, Message, SDT_MAX_TEXT);
MessageLen += LoadString(MyDllModuleHandle, IDS_DRIVER_NOMATCH2, Message + MessageLen, SDT_MAX_TEXT - MessageLen);
MessageLen += LoadString(MyDllModuleHandle, IDS_DRIVER_NOMATCH3, Message + MessageLen, SDT_MAX_TEXT - MessageLen);
if(MessageLen) {
if (MessageBox(hWnd, Message, Title, MB_YESNO | MB_TASKMODAL | MB_ICONEXCLAMATION |
MB_DEFBUTTON2) == IDYES) {
bRet = TRUE;
}
}
}
} else {
//
//I am not sure how we could get here and not have a DRIVER_NODE for the selected device.
//Maybe a different error message needs to be displayed here.
//
bRet = TRUE;
}
clean0:
Err = NO_ERROR;
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do
}
UnlockDeviceInfoSet(pDeviceInfoSet);
if(StringBuffers) {
MyFree(StringBuffers);
}
SetLastError(Err);
return bRet;
}
PDRIVER_NODE
pSetupGetSelectedDriverNode(
IN HWND hWnd,
IN PSP_DIALOGDATA lpdd,
IN INT iCur
)
/*++
Routine Description:
Arguments:
hwnd - Supplies the window handle of the wizard dialog page.
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
iCur - The index of the selected driver in the list view.
Return Value:
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDRIVER_NODE DriverNode = NULL;
LV_ITEM lviItem;
PDEVINFO_ELEM DevInfoElem;
//
// If the DD_FLAG_USE_DEVINFO_ELEM flag is not set then this device did not have
// we don't have a DevNode to validate the choosen ID against...so just return
// TRUE.
//
MYASSERT(lpdd);
if (!(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM))
return NULL;
if (!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return NULL;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
lviItem.mask = LVIF_PARAM;
lviItem.iItem = iCur;
lviItem.iSubItem = 0;
if(ListView_GetItem(lpdd->hwndDrvList, &lviItem)) {
DriverNode = GetDriverNodeFromLParam(pDeviceInfoSet, lpdd, lviItem.lParam);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do
}
UnlockDeviceInfoSet(pDeviceInfoSet);
return DriverNode;
}
VOID
SetSelectedDriverNode(
IN PSP_DIALOGDATA lpdd,
IN INT iCur
)
/*++
Routine Description:
This routine sets the selected driver for the currently selected device (or global
class driver list if no device selected) in the device information set referenced
in the SP_DIALOGDATA structure. If the DD_FLAG_USE_DEVINFO_ELEM flag in the
structure is set, then the driver is selected for the set or element based on the
DevInfoElem pointer instead of the currently selected one.
Arguments:
lpdd - Supplies the address of a dialog data structure that contains information
about the device information set being used.
iCur - Supplies the index within the driver listbox window containing the driver
to be selected.
Return Value:
None.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDRIVER_NODE DriverNode;
LV_ITEM lviItem;
PDEVINFO_ELEM DevInfoElem;
TCHAR ClassGuidString[GUID_STRING_LEN];
SP_DEVINFO_DATA DevInfoData;
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return;
}
try {
lviItem.mask = LVIF_PARAM;
lviItem.iItem = iCur;
lviItem.iSubItem = 0;
if(ListView_GetItem(lpdd->hwndDrvList, &lviItem)) {
DriverNode = GetDriverNodeFromLParam(pDeviceInfoSet, lpdd, lviItem.lParam);
} else {
DriverNode = NULL;
}
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
//
// If a driver node is being selected, update the device's class to ensure
// it matches the class of the INF containing the selected driver node.
//
if(DriverNode) {
//
// Get the INF class GUID for this driver node in string form, because
// this property is stored as a REG_SZ.
//
pSetupStringFromGuid(&(pDeviceInfoSet->GuidTable[DriverNode->GuidIndex]),
ClassGuidString,
SIZECHARS(ClassGuidString)
);
//
// Fill in a SP_DEVINFO_DATA structure for the upcoming call to
// SetupDiSetDeviceRegistryProperty.
//
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
&DevInfoData
);
if(!SetupDiSetDeviceRegistryProperty(lpdd->DevInfoSet,
&DevInfoData,
SPDRP_CLASSGUID,
(PBYTE)ClassGuidString,
sizeof(ClassGuidString))) {
//
// The class cannot be updated--don't change the selected driver.
//
goto clean0;
}
}
DevInfoElem->SelectedDriver = DriverNode;
if(DriverNode) {
DevInfoElem->SelectedDriverType = (lpdd->bShowCompat)
? SPDIT_COMPATDRIVER
: SPDIT_CLASSDRIVER;
} else {
DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
}
} else {
pDeviceInfoSet->SelectedClassDriver = DriverNode;
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do
}
UnlockDeviceInfoSet(pDeviceInfoSet);
}
DWORD
HandleSelectOEM(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
)
/*++
Routine Description:
This routine selects a new device based on a user-supplied path. Calling this
routine may cause a driver list to get built, which is a potentially slow operation.
Arguments:
hwndDlg - Supplies the window handle of the select device wizard page.
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
Return Value:
If successful, the return value is NO_ERROR, otherwise, it is an ERROR_* code.
--*/
{
PSP_DIALOGDATA lpdd;
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
SP_DEVINFO_DATA DevInfoData;
DWORD Err;
MYASSERT(ndwData);
lpdd = &(ndwData->ddData);
MYASSERT(lpdd);
if (!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return ERROR_INVALID_HANDLE;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
//
// If this is for a particular device, then initialize a device
// information structure to use for SelectOEMDriver.
//
if(DevInfoElem) {
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
&DevInfoData
);
}
//
// Unlock the device information set before popping up the OEM Driver Selection
// UI. Otherwise, our multi-threaded dialog will deadlock.
//
UnlockDeviceInfoSet(pDeviceInfoSet);
pDeviceInfoSet = NULL;
if((Err = SelectOEMDriver(hwndDlg,
lpdd->DevInfoSet,
DevInfoElem ? &DevInfoData : NULL,
!(lpdd->flags & DD_FLAG_IS_DIALOGBOX)
)) == ERROR_DI_DO_DEFAULT) {
if(DevInfoElem && DevInfoElem->CompatDriverHead) {
lpdd->bShowCompat = TRUE;
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_SHOW);
} else {
lpdd->bShowCompat = FALSE;
//
// Since we don't have any compatible drivers to show, we will hide the show compatible
// and show class selection buttons.
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
}
CheckDlgButton(hwndDlg,
IDC_NDW_PICKDEV_COMPAT,
lpdd->bShowCompat ? BST_CHECKED : BST_UNCHECKED
);
//
// Enable the UI. We turned it off when the user pressed the Have Disk... button
//
ToggleDialogControls(hwndDlg, ndwData, TRUE);
//
// Fill in the list to select from
//
FillInDeviceList(hwndDlg, lpdd);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = GetLastError();
//
// Access the pDeviceInfoSet variable so that the compiler will respect our statement
// ordering w.r.t. this value.
//
pDeviceInfoSet = pDeviceInfoSet;
}
if(pDeviceInfoSet) {
UnlockDeviceInfoSet(pDeviceInfoSet);
}
return Err;
}
#ifdef UNICODE
DWORD
SelectWindowsUpdateDriver(
IN HWND hwndParent, OPTIONAL
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PTSTR CDMPath,
IN BOOL IsWizard
)
/*++
Routine Description:
This is the worker routine that actually allows for the selection of an Windows Update driver.
Arguments:
hwndParent - Optionally, supplies the window handle that is to be the parent for any
selection UI. If this parameter is not supplied, then the hwndParent field of
the devinfo set or element will be used.
DeviceInfoSet - Supplies the handle of the device info set for which an Windows Update driver
selection is to be performed.
DeviceInfoData - Optionally, supplies the address of the device information element to
select a driver for. If this parameter is not supplied, then an OEM driver for
the global class driver list will be selected.
If a compatible driver was found for this device, the device information element
will have its class GUID updated upon return to reflect the device's new class.
IsWizard - Specifies whether this routine is being called in the context of a select
device wizard page.
Return Value:
If successful, the return value is NO_ERROR, otherwise, it is an ERROR_* code.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem = NULL;
PDEVINSTALL_PARAM_BLOCK dipb;
DWORD Err = NO_ERROR;
HWND hwndSave;
LONG DriverPathSave;
DWORD DriverPathFlagsSave;
BOOL bRestoreHwnd = FALSE, bRestoreDriverPath = FALSE, bUnlockDevInfoElem = FALSE;
UINT NewClassDriverCount;
TCHAR Title[MAX_TITLE_LEN];
DWORD SavedFlags;
DWORD SavedFlagsEx;
PDRIVER_NODE lpOrgCompat;
PDRIVER_NODE lpOrgCompatTail;
UINT OrgCompatCount;
PDRIVER_NODE lpOrgClass;
PDRIVER_NODE lpOrgClassTail;
UINT OrgClassCount;
PDRIVER_NODE lpOrgSel;
PDRIVER_NODE CurDriverNode;
PDRIVER_NODE DriverNodeHead = NULL;
DWORD dwOrgSelType;
DWORD dwOrgFlags;
DWORD dwOrgFlagsEx;
BOOL bRestoreDeviceInfo = FALSE;
LONG DriverPathId;
pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet);
try {
if(DeviceInfoData) {
//
// Then we're working with a particular device.
//
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL))) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// If the DevInfoElem isn't already locked, then lock it now, because
// we're going to be calling the class installer, and we don't want to
// allow it to delete this element!
//
if(!(DevInfoElem->DiElemFlags & DIE_IS_LOCKED)) {
DevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
bUnlockDevInfoElem = TRUE;
}
dipb = &(DevInfoElem->InstallParamBlock);
} else {
dipb = &(pDeviceInfoSet->InstallParamBlock);
}
//
// Make this selection window the parent window for Windows Update stuff
//
if(hwndParent) {
hwndSave = dipb->hwndParent;
dipb->hwndParent = hwndParent;
bRestoreHwnd = TRUE;
}
//
// Don't assume there is no old path. Save old one and
// pretend there is no old one in case of cancel.
//
DriverPathSave = dipb->DriverPath;
dipb->DriverPath = -1;
//
// Clear the DI_ENUMSINGLEINF flag, because we're going to be getting
// a path to a directory, _not_ to an individual INF. Also, clear the
// DI_COMPAT_FROM_CLASS flag, because we don't want to build the compatible
// driver list based on any class driver list.
//
DriverPathFlagsSave = dipb->Flags & (DI_ENUMSINGLEINF | DI_COMPAT_FROM_CLASS);
dipb->Flags &= ~(DI_ENUMSINGLEINF | DI_COMPAT_FROM_CLASS);
bRestoreDriverPath = TRUE;
//
// Set the DriverPath to the path returned by CDM
//
if((DriverPathId = pStringTableAddString(
pDeviceInfoSet->StringTable,
CDMPath,
STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
NULL,0)) == -1) {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
} else {
dipb->DriverPath = DriverPathId;
}
//
// Save the Original List info, in case we get
// an empty list on the Windows Update information.
//
// (Note: we don't attempt to save/restore our driver enumeration hints)
//
if(DevInfoElem) {
lpOrgCompat = DevInfoElem->CompatDriverHead;
lpOrgCompatTail = DevInfoElem->CompatDriverTail;
OrgCompatCount = DevInfoElem->CompatDriverCount;
lpOrgClass = DevInfoElem->ClassDriverHead;
lpOrgClassTail = DevInfoElem->ClassDriverTail;
OrgClassCount = DevInfoElem->ClassDriverCount;
lpOrgSel = DevInfoElem->SelectedDriver;
dwOrgSelType = DevInfoElem->SelectedDriverType;
} else {
lpOrgClass = pDeviceInfoSet->ClassDriverHead;
lpOrgClassTail = pDeviceInfoSet->ClassDriverTail;
OrgClassCount = pDeviceInfoSet->ClassDriverCount;
lpOrgSel = pDeviceInfoSet->SelectedClassDriver;
dwOrgSelType = lpOrgSel ? SPDIT_CLASSDRIVER : SPDIT_NODRIVER;
}
dwOrgFlags = dipb->Flags;
dwOrgFlagsEx = dipb->FlagsEx;
bRestoreDeviceInfo = TRUE;
if(DevInfoElem) {
DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
DevInfoElem->CompatDriverCount = 0;
DevInfoElem->CompatDriverEnumHint = NULL;
DevInfoElem->CompatDriverEnumHintIndex = INVALID_ENUM_INDEX;
DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
DevInfoElem->ClassDriverCount = 0;
DevInfoElem->ClassDriverEnumHint = NULL;
DevInfoElem->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
DevInfoElem->SelectedDriver = NULL;
DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
} else {
lpOrgCompat = NULL; // just so we won't ever try to free this list.
pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
pDeviceInfoSet->ClassDriverCount = 0;
pDeviceInfoSet->ClassDriverEnumHint = NULL;
pDeviceInfoSet->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
pDeviceInfoSet->SelectedClassDriver = NULL;
}
SavedFlags = dipb->Flags & (DI_SHOWOEM | DI_NODI_DEFAULTACTION);
SavedFlagsEx = dipb->FlagsEx & (DI_FLAGSEX_SHOWWINDOWSUPDATE);
dipb->Flags &= ~(DI_DIDCOMPAT | DI_DIDCLASS | DI_MULTMFGS | DI_SHOWOEM);
dipb->FlagsEx &= ~(DI_FLAGSEX_DIDINFOLIST | DI_FLAGSEX_DIDCOMPATINFO | DI_FLAGSEX_SHOWWINDOWSUPDATE);
if(IsWizard) {
//
// We don't want default action taken in the wizard case.
//
dipb->Flags |= DI_NODI_DEFAULTACTION;
}
//
// Unlock the HDEVINFO before handling the Select Device. Otherwise, our
// multi-threaded dialog will deadlock!
//
UnlockDeviceInfoSet(pDeviceInfoSet);
pDeviceInfoSet = NULL;
if(_SetupDiCallClassInstaller(DIF_SELECTDEVICE,
DeviceInfoSet,
DeviceInfoData,
CALLCI_LOAD_HELPERS | CALLCI_CALL_HELPERS)) {
Err = NO_ERROR;
} else {
Err = GetLastError();
}
//
// Now, re-acquire the lock on our device information set.
//
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
if (Err == NO_ERROR) {
Err = ERROR_INVALID_HANDLE;
}
}
//
// Restore the saved flags.
//
dipb->Flags = (dipb->Flags & ~(DI_SHOWOEM | DI_NODI_DEFAULTACTION)) | SavedFlags;
dipb->FlagsEx = (dipb->FlagsEx & ~(DI_FLAGSEX_SHOWWINDOWSUPDATE)) | SavedFlagsEx;
//
// If the class installer returned ERROR_DI_DO_DEFAULT, then
// they either did not process the DIF_SELECTDEVICE, or they
// have setup our device info structure with an OEM INF.
//
switch(Err) {
case ERROR_DI_DO_DEFAULT :
//
// This case is only handled if we're in a wizard. Otherwise, send it down
// for default processing.
//
if(!IsWizard) {
goto DefaultHandling;
}
//
// This will be the most likely return, since we are not allowing the
// default handler to be called. So we will build a new class Drv list
// If it is empty we will ask again, otherwise we will accept the new
// selection and go on.
//
SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Any drivers we find are Internet drivers.
//
dipb->FlagsEx |= DI_FLAGSEX_INET_DRIVER;
SetupDiBuildDriverInfoList(DeviceInfoSet,
DeviceInfoData,
SPDIT_CLASSDRIVER
);
dipb->FlagsEx &= ~DI_FLAGSEX_INET_DRIVER;
SetCursor(LoadCursor(NULL, IDC_ARROW));
if(DevInfoElem) {
NewClassDriverCount = DevInfoElem->ClassDriverCount;
DriverNodeHead = DevInfoElem->ClassDriverHead;
} else {
NewClassDriverCount = pDeviceInfoSet->ClassDriverCount;
DriverNodeHead = pDeviceInfoSet->ClassDriverHead;
}
if(NewClassDriverCount) {
//
//
//
if (DriverNodeHead) {
for (CurDriverNode=DriverNodeHead;
CurDriverNode;
CurDriverNode = CurDriverNode->Next) {
CurDriverNode->Flags |= DNF_INF_IS_SIGNED;
}
}
} else {
//
// Error.
//
if(!LoadString(MyDllModuleHandle,
IDS_SELECT_DEVICE,
Title,
SIZECHARS(Title))) {
*Title = TEXT('\0');
}
FormatMessageBox(MyDllModuleHandle,
NULL,
MSG_NO_DEVICEINFO_ERROR,
Title,
MB_OK | MB_TASKMODAL
);
//
// Clean up anything that happened to get put in here.
//
if(DevInfoElem &&
(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDCOMPATINFO)) {
//
// The class installer built a compatible driver list--kill it here.
//
DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
DevInfoElem->CompatDriverCount = 0;
DevInfoElem->InstallParamBlock.Flags &= ~DI_DIDCOMPAT;
DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
DevInfoElem->SelectedDriver = NULL;
DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
}
dipb->DriverPath = -1;
break;
}
//
// Allow to fall through to handling of NO_ERROR which does clean-up for us.
//
case NO_ERROR :
//
// Destroy the original lists
//
if(bRestoreDeviceInfo) {
DestroyDriverNodes(lpOrgCompat, pDeviceInfoSet);
DereferenceClassDriverList(pDeviceInfoSet, lpOrgClass);
bRestoreDeviceInfo = FALSE;
}
bRestoreDriverPath = FALSE;
break;
case ERROR_DI_BAD_PATH :
//
// Pop up an error messagebox, and then leave
//
if(!LoadString(MyDllModuleHandle,
IDS_SELECT_DEVICE,
Title,
SIZECHARS(Title))) {
*Title = TEXT('\0');
}
FormatMessageBox(MyDllModuleHandle,
NULL,
MSG_NO_DEVICEINFO_ERROR,
Title,
MB_OK | MB_TASKMODAL
);
dipb->DriverPath = -1;
//
// Allow to fall through to default processing to delete the current
// driver list(s).
//
default :
DefaultHandling:
//
// Destroy the current driver list(s).
//
if(DevInfoElem) {
DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
DevInfoElem->CompatDriverCount = 0;
DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
DevInfoElem->ClassDriverCount = 0;
DevInfoElem->SelectedDriver = NULL;
DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
} else {
DereferenceClassDriverList(pDeviceInfoSet, pDeviceInfoSet->ClassDriverHead);
pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
pDeviceInfoSet->ClassDriverCount = 0;
pDeviceInfoSet->SelectedClassDriver = NULL;
}
}
clean0: ; // nothing to do
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = GetLastError();
//
// Access the following variables so that the compiler will respect
// the statement ordering in the try clause.
//
bRestoreDeviceInfo = bRestoreDeviceInfo;
bUnlockDevInfoElem = bUnlockDevInfoElem;
bRestoreHwnd = bRestoreHwnd;
bRestoreDriverPath = bRestoreDriverPath;
pDeviceInfoSet = pDeviceInfoSet;
}
//
// If we need to restore any state, then we must make sure that we have the HDEVINFO
// locked.
//
if(bRestoreDeviceInfo || bUnlockDevInfoElem || bRestoreHwnd || bRestoreDriverPath) {
if(!pDeviceInfoSet && !(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
} else {
try {
//
// If necessary, restore the original list(s).
//
if(bRestoreDeviceInfo) {
if(DevInfoElem) {
DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
DevInfoElem->CompatDriverHead = lpOrgCompat;
DevInfoElem->CompatDriverTail = lpOrgCompatTail;
DevInfoElem->CompatDriverCount = OrgCompatCount;
lpOrgCompat = NULL;
DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
DevInfoElem->ClassDriverHead = lpOrgClass;
DevInfoElem->ClassDriverTail = lpOrgClassTail;
DevInfoElem->ClassDriverCount = OrgClassCount;
lpOrgClass = NULL;
DevInfoElem->SelectedDriver = lpOrgSel;
DevInfoElem->SelectedDriverType = dwOrgSelType;
} else {
DereferenceClassDriverList(pDeviceInfoSet, pDeviceInfoSet->ClassDriverHead);
pDeviceInfoSet->ClassDriverHead = lpOrgClass;
pDeviceInfoSet->ClassDriverTail = lpOrgClassTail;
pDeviceInfoSet->ClassDriverCount = OrgClassCount;
lpOrgClass = NULL;
pDeviceInfoSet->SelectedClassDriver = lpOrgSel;
}
dipb->Flags = dwOrgFlags;
dipb->FlagsEx = dwOrgFlagsEx;
}
//
// If we locked the DevInfoElem just for this API, then unlock it now.
//
if(bUnlockDevInfoElem) {
MYASSERT(DevInfoElem);
DevInfoElem->DiElemFlags &= ~DIE_IS_LOCKED;
}
//
// If the install param block needs its parent hwnd restored, do so now.
//
if(bRestoreHwnd) {
dipb->hwndParent = hwndSave;
}
//
// Likewise, restore the old driver path if necessary.
//
if(bRestoreDriverPath) {
dipb->DriverPath = DriverPathSave;
dipb->Flags |= DriverPathFlagsSave;
}
; // nothing to do
} except(EXCEPTION_EXECUTE_HANDLER) {
if(bRestoreDeviceInfo) {
//
// If we hit an exception before we got a chance to restore any of our stored-away
// driver lists, then clean those up here.
//
if(DevInfoElem) {
if(lpOrgCompat) {
DestroyDriverNodes(lpOrgCompat, pDeviceInfoSet);
}
if(lpOrgClass) {
DereferenceClassDriverList(pDeviceInfoSet, lpOrgClass);
}
} else {
if(lpOrgClass) {
DereferenceClassDriverList(pDeviceInfoSet, lpOrgClass);
}
}
}
}
}
}
if(pDeviceInfoSet) {
UnlockDeviceInfoSet(pDeviceInfoSet);
}
return Err;
}
DWORD
HandleWindowsUpdate(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
)
/*++
Routine Description:
This routine selects a new driver based on a list from INF file(s) that get
downloaded from the Windows Update Internet site.
Arguments:
hwndDlg - Supplies the window handle of the select device wizard page.
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
Return Value:
If successful, the return value is NO_ERROR, otherwise, it is an ERROR_* code.
--*/
{
PSP_DIALOGDATA lpdd;
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINSTALL_PARAM_BLOCK dipb;
SP_WINDOWSUPDATE_PARAMS WindowsUpdateParams;
PDEVINFO_ELEM DevInfoElem;
SP_DEVINFO_DATA DevInfoData;
TCHAR CDMPath[MAX_PATH];
ULONG BufferLen;
DOWNLOADINFO DownloadInfo;
HMODULE hModCDM;
DOWNLOAD_UPDATED_FILES_PROC DownloadUpdateFilesProc;
DWORD Err;
TCHAR Title[MAX_TITLE_LEN];
SPFUSIONINSTANCE spFusionInstance;
MYASSERT(ndwData);
lpdd = &(ndwData->ddData);
MYASSERT(lpdd);
pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet);
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
//
// If this is for a particular device, then initialize a device
// information structure.
//
if(DevInfoElem) {
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
&DevInfoData
);
dipb = &(DevInfoElem->InstallParamBlock);
} else {
dipb = &(pDeviceInfoSet->InstallParamBlock);
}
//
// Call the class installer to get the package ID and so it can open
// a handle to the Windows Update server.
//
memset(&WindowsUpdateParams, 0, sizeof(SP_WINDOWSUPDATE_PARAMS));
WindowsUpdateParams.ClassInstallHeader.InstallFunction = DIF_GETWINDOWSUPDATEINFO;
WindowsUpdateParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
if ((Err = DoInstallActionWithParams(DIF_GETWINDOWSUPDATEINFO,
pDeviceInfoSet,
DevInfoElem ? &DevInfoData : NULL,
&WindowsUpdateParams.ClassInstallHeader,
sizeof(SP_WINDOWSUPDATE_PARAMS),
INSTALLACTION_CALL_CI)) == NO_ERROR) {
//
// We now have a PackageId and a handle to the Windows Update server
//
//
// Fill In the DOWNLOADINFO structure to pass to CDM.DLL
//
ZeroMemory(&DownloadInfo, sizeof(DOWNLOADINFO));
DownloadInfo.dwDownloadInfoSize = sizeof(DOWNLOADINFO);
DownloadInfo.lpFile = NULL;
DownloadInfo.lpHardwareIDs = (LPCWSTR)WindowsUpdateParams.PackageId;
DownloadInfo.lpDeviceInstanceID = NULL;
GetVersionEx((OSVERSIONINFOW *)&DownloadInfo.OSVersionInfo);
//
// Set dwArchitecture to PROCESSOR_ARCHITECTURE_UNKNOWN, this
// causes Windows Update to check get the architecture of the
// machine itself. You only need to explictly set the value if
// you want to download drivers for a different architecture then
// the machine this is running on.
//
DownloadInfo.dwArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
DownloadInfo.dwFlags = 0;
DownloadInfo.dwClientID = 0;
DownloadInfo.localid = 0;
CDMPath[0] = TEXT('\0');
spFusionEnterContext(NULL,&spFusionInstance);
if ((hModCDM = LoadLibrary(TEXT("cdm.dll"))) &&
(DownloadUpdateFilesProc = (PVOID)GetProcAddress(hModCDM, "DownloadUpdatedFiles")) &&
(DownloadUpdateFilesProc(WindowsUpdateParams.CDMContext,
hwndDlg,
&DownloadInfo,
CDMPath,
sizeof(CDMPath),
&BufferLen)) &&
(CDMPath[0] != TEXT('\0'))) {
//
// We successfully downloaded a package from Windows Update
//
spFusionLeaveContext(&spFusionInstance);
//
// Unlock the device information set before popping up the OEM Driver Selection
// UI. Otherwise, our multi-threaded dialog will deadlock.
//
UnlockDeviceInfoSet(pDeviceInfoSet);
pDeviceInfoSet = NULL;
if((Err = SelectWindowsUpdateDriver(hwndDlg,
lpdd->DevInfoSet,
DevInfoElem ? &DevInfoData : NULL,
CDMPath,
!(lpdd->flags & DD_FLAG_IS_DIALOGBOX)
)) == ERROR_DI_DO_DEFAULT) {
//
// Fill in the list to select from
//
lpdd->bShowCompat = FALSE;
CheckDlgButton(hwndDlg,
IDC_NDW_PICKDEV_COMPAT,
BST_UNCHECKED
);
//
// Enable the UI. We turned it off when the user pressed the Windows Update... button
//
ToggleDialogControls(hwndDlg, ndwData, TRUE);
FillInDeviceList(hwndDlg, lpdd);
//
// Since we only show the class list when selecting from
// Windows Update, hide the selection buttons.
//
ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
}
} else {
spFusionLeaveContext(&spFusionInstance);
//
// Something failed when we tried to download the INF from the Internet
//
Err = ERROR_INVALID_PARAMETER;
//
// Pop up an error messagebox, then go try again.
//
if(!LoadString(MyDllModuleHandle,
IDS_SELECT_DEVICE,
Title,
SIZECHARS(Title))) {
*Title = TEXT('\0');
}
FormatMessageBox(MyDllModuleHandle,
NULL,
MSG_NO_DEVICEINFO_ERROR,
Title,
MB_OK | MB_TASKMODAL
);
}
if (hModCDM) {
spFusionEnterContext(NULL,&spFusionInstance);
FreeLibrary(hModCDM);
spFusionLeaveContext(&spFusionInstance);
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = GetLastError();
//
// Access the pDeviceInfoSet variable so that the compiler will respect our statement
// ordering w.r.t. this value.
//
pDeviceInfoSet = pDeviceInfoSet;
}
if(pDeviceInfoSet) {
UnlockDeviceInfoSet(pDeviceInfoSet);
}
return Err;
}
#else
DWORD
HandleWindowsUpdate(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData
)
{
return ERROR_INVALID_PARAMETER;
}
#endif
PNEWDEVWIZ_DATA
GetNewDevWizDataFromPsPage(
LPPROPSHEETPAGE ppsp
)
/*++
Routine Description:
This routine retrieves a pointer to a NEWDEVWIZDATA structure to be used by a
wizard page dialog proc. It is called during the WM_INITDIALOG handling.
Arguments:
Page - Property sheet page structure for this wizard page.
Return Value:
If success, a pointer to the structure, NULL otherwise.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PVOID WizObjectId;
PWIZPAGE_OBJECT CurWizObject = NULL;
//
// Access the device info set handle stored in the propsheetpage's lParam.
//
MYASSERT(ppsp);
if(pDeviceInfoSet = AccessDeviceInfoSet((HDEVINFO)(ppsp->lParam))) {
try {
//
// The ObjectID (pointer, actually) for the corresponding wizard
// object for this page is stored at the end of the ppsp structure.
// Retrieve this now, and look for it in the devinfo set's list of
// wizard objects.
//
WizObjectId = *((PVOID *)(&(((PBYTE)ppsp)[sizeof(PROPSHEETPAGE)])));
for(CurWizObject = pDeviceInfoSet->WizPageList;
CurWizObject;
CurWizObject = CurWizObject->Next) {
if(WizObjectId == CurWizObject) {
//
// We found our object.
//
break;
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do
}
UnlockDeviceInfoSet(pDeviceInfoSet);
}
return CurWizObject ? CurWizObject->ndwData : NULL;
}
BOOL
WINAPI
SetupDiSelectDevice(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
)
/*++
Routine Description:
Default handler for DIF_SELECTDEVICE
This routine will handle the UI for allowing a user to select a driver
for the specified device information set or element. By using the Flags field
of the installation parameter block struct, the caller can specify special
handling of the UI, such as allowing selecting from OEM disks.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set for which a
driver is to be selected.
DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
structure for which a driver is to be selected. If this parameter is not
specified, then a driver will be selected for the global class driver list
associated with the device information set itself.
This is an IN OUT parameter because the class GUID for the device will be
updated to reflect the class of the most-compatible driver, if a compatible
driver list was built.
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
DWORD Err;
PDEVINFO_ELEM DevInfoElem = NULL;
PDEVINSTALL_PARAM_BLOCK dipb;
WIZPAGE_OBJECT WizPageObject;
NEWDEVWIZ_DATA ndwData;
PWIZPAGE_OBJECT CurWizObject, PrevWizObject;
//
// Store the address of the corresponding wizard object at the
// end of the PROPSHEETPAGE buffer.
//
BYTE pspBuffer[sizeof(PROPSHEETPAGE) + sizeof(PVOID)];
LPPROPSHEETPAGE Page = (LPPROPSHEETPAGE)pspBuffer;
//
// Make sure we're running interactively.
//
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return FALSE;
}
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
//
// This routine cannot be called when the lock level is nested (i.e., > 1). This
// is explicitly disallowed, so that our multi-threaded dialog won't deadlock.
//
if(pDeviceInfoSet->LockRefCount > 1) {
Err = ERROR_DEVINFO_LIST_LOCKED;
goto clean0;
}
if(DeviceInfoData) {
//
// Special check to make sure we aren't being passed a zombie (different from
// phantom, the zombie devinfo element is one whose corresponding devinst was
// deleted via SetupDiRemoveDevice, but who lingers on until the caller kills
// it via SetupDiDeleteDeviceInfo or SetupDiDestroyDeviceInfoList).
//
if(!DeviceInfoData->DevInst) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// Then we are to select a driver for a particular device.
//
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL))) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
dipb = &(DevInfoElem->InstallParamBlock);
} else {
dipb = &(pDeviceInfoSet->InstallParamBlock);
}
ZeroMemory(&ndwData, sizeof(ndwData));
ndwData.ddData.iCurDesc = -1;
ndwData.ddData.DevInfoSet = DeviceInfoSet;
ndwData.ddData.DevInfoElem = DevInfoElem;
ndwData.ddData.flags = DD_FLAG_USE_DEVINFO_ELEM | DD_FLAG_IS_DIALOGBOX;
WizPageObject.RefCount = 1;
WizPageObject.ndwData = &ndwData;
//
// We're safe in placing this stack object in the devinfo set's linked
// list, since nobody will ever attempt to free it.
//
WizPageObject.Next = pDeviceInfoSet->WizPageList;
pDeviceInfoSet->WizPageList = &WizPageObject;
//
// Since we're using the same code as the Add New Device Wizard, we
// have to supply a LPROPSHEETPAGE as the lParam to the DialogProc.
// (All we care about is the lParam field, and the DWORD at the end
// of the buffer.)
//
Page->lParam = (LPARAM)DeviceInfoSet;
*((PVOID *)(&(pspBuffer[sizeof(PROPSHEETPAGE)]))) = &WizPageObject;
//
// Release the lock, so other stuff can happen while this dialog is up.
//
UnlockDeviceInfoSet(pDeviceInfoSet);
pDeviceInfoSet = NULL;
Err = (DWORD)DialogBoxParam(MyDllModuleHandle,
MAKEINTRESOURCE(DLG_DEVINSTALL),
dipb->hwndParent,
SelectDeviceDlgProc,
(LPARAM)Page
);
//
// Re-acquire the devinfo set lock.
//
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
//
// should never hit this code path
// this would imply another thread messed this handle up
//
MYASSERT(pDeviceInfoSet);
Err = ERROR_INVALID_HANDLE;
goto clean0;
}
//
// Now remove the wizard page object from the devinfo set's list. We can't
// assume that it's still at the head of the list, since someone else couldn've
// added another page.
//
for(CurWizObject = pDeviceInfoSet->WizPageList, PrevWizObject = NULL;
CurWizObject;
PrevWizObject = CurWizObject, CurWizObject = CurWizObject->Next) {
if(CurWizObject == &WizPageObject) {
break;
}
}
MYASSERT(CurWizObject);
if(PrevWizObject) {
PrevWizObject->Next = CurWizObject->Next;
} else {
pDeviceInfoSet->WizPageList = CurWizObject->Next;
}
if(DeviceInfoData) {
//
// Update the caller's device information element with its (potentially) new class.
//
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
DeviceInfoData
);
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
//
// Access the pDeviceInfoSet variable so that the compiler will respect
// the statement ordering in the try clause.
//
pDeviceInfoSet = pDeviceInfoSet;
}
if(pDeviceInfoSet) {
UnlockDeviceInfoSet(pDeviceInfoSet);
}
SetLastError(Err);
return(Err == NO_ERROR);
}
BOOL
bNoDevsToShow(
IN PDEVINFO_ELEM DevInfoElem
)
/*++
Routine Description:
This routine determines whether or not there are any compatible devices to be
displayed for the specified devinfo element.
Arguments:
DevInfoElem - Supplies the address of a devinfo element to check.
Return Value:
If there are no devices to show, the return value is TRUE.
If there is at least one device (driver node) without the DNF_EXCLUDEFROMLIST flag
set, the return value is FALSE.
--*/
{
PDRIVER_NODE CurDriverNode;
for(CurDriverNode = DevInfoElem->CompatDriverHead;
CurDriverNode;
CurDriverNode = CurDriverNode->Next) {
if (!(CurDriverNode->Flags & DNF_OLD_INET_DRIVER) &&
!(CurDriverNode->Flags & DNF_BAD_DRIVER) &&
(!(CurDriverNode->Flags & DNF_EXCLUDEFROMLIST) ||
(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS))) {
return FALSE;
}
}
return TRUE;
}
VOID
OnCancel(
IN PNEWDEVWIZ_DATA ndwData
)
/*++
Routine Description:
This routine is only called in the select device dialog (not wizard) case. Its
sole purpose is to destroy any driver lists that weren't present before
SetupDiSelectDevice was called.
Arguments:
ndwData - Supplies the address of a data structure containing information on the
driver lists to be (possibly) destroyed.
Return Value:
None.
--*/
{
PSP_DIALOGDATA lpdd;
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
PDEVINSTALL_PARAM_BLOCK dipb;
DWORD SelectedDriverType = SPDIT_NODRIVER;
MYASSERT(ndwData);
lpdd = &(ndwData->ddData);
MYASSERT(lpdd);
if (!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
if(lpdd->bKeeplpSelectedDrv) {
SelectedDriverType = DevInfoElem->SelectedDriverType;
} else {
DevInfoElem->SelectedDriver = NULL;
DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
}
if((DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) &&
!lpdd->bKeeplpClassDrvList && (SelectedDriverType != SPDIT_CLASSDRIVER)) {
DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
DevInfoElem->ClassDriverCount = 0;
DevInfoElem->ClassDriverEnumHint = NULL;
DevInfoElem->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
DevInfoElem->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
}
if((DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDCOMPATINFO) &&
!lpdd->bKeeplpCompatDrvList && (SelectedDriverType != SPDIT_COMPATDRIVER)) {
DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
DevInfoElem->CompatDriverCount = 0;
DevInfoElem->CompatDriverEnumHint = NULL;
DevInfoElem->CompatDriverEnumHintIndex = INVALID_ENUM_INDEX;
DevInfoElem->InstallParamBlock.Flags &= ~DI_DIDCOMPAT;
DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
}
} else {
if(lpdd->bKeeplpSelectedDrv) {
if(pDeviceInfoSet->SelectedClassDriver) {
SelectedDriverType = SPDIT_CLASSDRIVER;
}
} else {
pDeviceInfoSet->SelectedClassDriver = NULL;
}
if((pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) &&
!lpdd->bKeeplpClassDrvList && (SelectedDriverType != SPDIT_CLASSDRIVER)) {
DereferenceClassDriverList(pDeviceInfoSet, pDeviceInfoSet->ClassDriverHead);
pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
pDeviceInfoSet->ClassDriverCount = 0;
pDeviceInfoSet->ClassDriverEnumHint = NULL;
pDeviceInfoSet->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
pDeviceInfoSet->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
pDeviceInfoSet->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do
}
UnlockDeviceInfoSet(pDeviceInfoSet);
}
LONG
GetCurDesc(
IN PSP_DIALOGDATA lpdd
)
/*++
Routine Description:
This routine returns the (case-insensitive) string table index for the description
of the currently selected driver. This is used to select a particular entry in a
listview control.
Arguments:
lpdd - Supplies the address of a dialog data structure that contains information
about the device information set being used.
Return Value:
The string table ID for the device description, as stored in the currently-selected
driver node.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
LONG ret;
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return -1;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
ret = DevInfoElem->SelectedDriver
? DevInfoElem->SelectedDriver->DevDescription
: -1;
} else {
ret = pDeviceInfoSet->SelectedClassDriver
? pDeviceInfoSet->SelectedClassDriver->DevDescription
: -1;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
ret = -1;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
return ret;
}
VOID
__cdecl
ClassDriverSearchThread(
IN PVOID Context
)
/*++
Routine Description:
Thread entry point to build a class driver list asynchronously to the main
thread which is displaying a Select Device dialog. This thread will free
the memory containing its context, so the main thread should not access it
after passing it to this thread.
Arguments:
Context - supplies driver search context.
Return Value:
None.
--*/
{
PCLASSDRV_THREAD_CONTEXT ClassDrvThreadContext = Context;
SP_DEVINSTALL_PARAMS DeviceInstallParams;
BOOL b;
DWORD Err;
//
// OR in the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag so that we don't include
// old internet drivers in the list that we get back.
//
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if (SetupDiGetDeviceInstallParams(ClassDrvThreadContext->DeviceInfoSet,
&(ClassDrvThreadContext->DeviceInfoData),
&DeviceInstallParams
))
{
DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
SetupDiSetDeviceInstallParams(ClassDrvThreadContext->DeviceInfoSet,
&(ClassDrvThreadContext->DeviceInfoData),
&DeviceInstallParams
);
}
if(b = SetupDiBuildDriverInfoList(ClassDrvThreadContext->DeviceInfoSet,
&(ClassDrvThreadContext->DeviceInfoData),
SPDIT_CLASSDRIVER)) {
Err = NO_ERROR;
} else {
Err = GetLastError();
}
//
// Now send a message to our notification window informing them of the outcome.
//
PostMessage(ClassDrvThreadContext->NotificationWindow,
WMX_CLASSDRVLIST_DONE,
(WPARAM)b,
(LPARAM)Err
);
MyFree(Context);
//
// Done.
//
_endthread();
}
BOOL
pSetupIsClassDriverListBuilt(
IN PSP_DIALOGDATA lpdd
)
/*++
Routine Description:
This routine determines whether or not a class driver list has already been
built for the specified dialog data.
Arguments:
lpdd - Supplies the address of a dialog data buffer that is being queried for
the presence of a class driver list.
Return Value:
If a class driver list has already been built, the return value is TRUE, otherwise,
it is FALSE.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
BOOL b = FALSE;
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return FALSE;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if(DevInfoElem) {
b = DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST;
} else {
b = pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do.
}
UnlockDeviceInfoSet(pDeviceInfoSet);
return b;
}
VOID
pSetupDevInfoDataFromDialogData(
IN PSP_DIALOGDATA lpdd,
OUT PSP_DEVINFO_DATA DeviceInfoData
)
/*++
Routine Description:
This routine fills in a SP_DEVINFO_DATA structure based on the device information
element specified in the supplied dialog data.
Arguments:
lpdd - Supplies the address of a dialog data buffer that specifies a devinfo element
to be used in filling in the DeviceInfoData buffer.
DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure that is filled
in with information about the devinfo element specified in the dialog data.
Return Value:
None.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
//
// The dialog data had better be referencing a devinfo element!
//
MYASSERT(DevInfoElem);
DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet, DevInfoElem, DeviceInfoData);
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// What to do, what to do???
// We'll just invalidate the DeviceInfoData structure.
//
DeviceInfoData->cbSize = 0;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
}
VOID
CleanupDriverLists(
IN OUT PNEWDEVWIZ_DATA ndwData
)
/*++
Routine Description:
This routine will destroy both the class and compatible driver lists that were
created while the wizard page was up.
Arguments:
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
Return Value:
None.
--*/
{
PSP_DIALOGDATA lpdd;
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
PDEVINSTALL_PARAM_BLOCK dipb;
SP_DEVINFO_DATA DeviceInfoData;
MYASSERT(ndwData);
lpdd = &(ndwData->ddData);
MYASSERT(lpdd);
if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
//
// should never hit this code path
//
MYASSERT(pDeviceInfoSet);
return;
}
try {
if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
DevInfoElem = lpdd->DevInfoElem;
} else {
DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
}
if (DevInfoElem) {
//
// Initialize a SP_DEVINFO_DATA buffer to use as an argument to
// SetupDiDestroyDriverInfoList.
//
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
DevInfoElem,
&DeviceInfoData
);
//
// We need to reset the DriverPath so that if we come back into the wizard
// we will rebuild from the correct directory. Otherwise we will be stuck
// with the Have Disk... path that the user entered.
//
DevInfoElem->InstallParamBlock.DriverPath = -1;
} else {
pDeviceInfoSet->InstallParamBlock.DriverPath = -1;
}
SetupDiDestroyDriverInfoList(pDeviceInfoSet,
DevInfoElem ? &DeviceInfoData : NULL,
SPDIT_COMPATDRIVER
);
SetupDiDestroyDriverInfoList(pDeviceInfoSet,
DevInfoElem ? &DeviceInfoData : NULL,
SPDIT_CLASSDRIVER
);
} except(EXCEPTION_EXECUTE_HANDLER) {
; // nothing to do.
}
UnlockDeviceInfoSet(pDeviceInfoSet);
}
VOID
ToggleDialogControls(
IN HWND hwndDlg,
IN OUT PNEWDEVWIZ_DATA ndwData,
IN BOOL Enable
)
/*++
Routine Description:
This routine either enables or disables all controls on a Select Device dialog box,
depending on the value of Enable.
Arguments:
hwndDlg - Supplies the handle of the Select Device dialog
ndwData - Supplies the address of a New Device Wizard data block to be used
during the processing of this message.
Enable - If TRUE, then enable all controls (with possible exception of "Show all devices"
radio button (if class list search failed). If FALSE, disable all controls.
Return Value:
None.
--*/
{
//
// If we're enabling controls, make sure we only enable the "Show compatible
// drivers" check box if we successfully built a class list.
//
if(Enable) {
if(!((ndwData->ddData).flags & DD_FLAG_CLASSLIST_FAILED)) {
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), TRUE);
} else {
//
// The class list failed to build, so we will show the compatible
// list only. Check and disable the show compatible check box.
//
(ndwData->ddData).bShowCompat = TRUE;
CheckDlgButton(hwndDlg, IDC_NDW_PICKDEV_COMPAT, BST_CHECKED);
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
}
} else {
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
}
EnableWindow((ndwData->ddData).hwndDrvList, Enable);
EnableWindow((ndwData->ddData).hwndMfgList, Enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_HAVEDISK), Enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_WINDOWSUPDATE), Enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), Enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), Enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), Enable);
if ((ndwData->ddData).flags & DD_FLAG_IS_DIALOGBOX) {
EnableWindow(GetDlgItem(hwndDlg, IDOK), Enable);
EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), Enable);
} else {
INT WizardFlags = 0;
if (Enable) {
//
// Don't show the back button if we are in express mode.
//
if(!((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) ||
!((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) ||
((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
WizardFlags |= PSWIZB_BACK;
}
//
// Show the Next button if there is at least one driver selected in the
// list view.
//
if (ListView_GetSelectedCount((ndwData->ddData).hwndDrvList) > 0) {
WizardFlags |= PSWIZB_NEXT;
}
}
PropSheet_SetWizButtons(GetParent(hwndDlg), WizardFlags);
EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), Enable);
}
}
BOOL
CDMIsInternetAvailable(
void
)
/*++
Routine Description:
This routine will return TRUE or FALSE based on if this machine can get to the
Internet or not.
Arguments:
None
Return Value:
TRUE if the machine can get to the Internet.
FALSE if the machine can NOT get to the Internet.
--*/
{
BOOL IsInternetAvailable = FALSE;
OSVERSIONINFOEX info;
HKEY hKey;
DWORD Policy;
ULONG cbData;
HMODULE hModCDM = NULL;
CDM_INTERNET_AVAILABLE_PROC CdmInternetAvailable;
SPFUSIONINSTANCE spFusionInstance;
#ifdef UNICODE
//
// If this is DataCenter then never call CDM!
//
info.dwOSVersionInfoSize = sizeof(info);
if (GetVersionEx((POSVERSIONINFOW)&info) &&
(info.wSuiteMask & VER_SUITE_DATACENTER)) {
return FALSE;
}
#endif
//
// Check the DontSearchWindowsUpdate DriverSearching policy.
//
if (RegOpenKeyEx(HKEY_CURRENT_USER,
TEXT("Software\\Policies\\Microsoft\\Windows\\DriverSearching"),
0,
KEY_READ,
&hKey
) == ERROR_SUCCESS) {
Policy = 0;
cbData = sizeof(Policy);
if (RegQueryValueEx(hKey,
TEXT("DontSearchWindowsUpdate"),
NULL,
NULL,
(LPBYTE)&Policy,
&cbData) != ERROR_SUCCESS) {
Policy = 0;
}
RegCloseKey(hKey);
//
// If the DontSearchWindowsUpdate policy is set then return FALSE.
//
if (Policy) {
return FALSE;
}
}
spFusionEnterContext(NULL,&spFusionInstance);
if ((hModCDM = LoadLibrary(TEXT("cdm.dll"))) &&
(CdmInternetAvailable = (PVOID)GetProcAddress(hModCDM, "DownloadIsInternetAvailable")) &&
(CdmInternetAvailable())) {
IsInternetAvailable = TRUE;
}
if (hModCDM) {
FreeLibrary(hModCDM);
}
spFusionLeaveContext(&spFusionInstance);
return IsInternetAvailable;
}