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.
638 lines
19 KiB
638 lines
19 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation
|
|
//
|
|
// File: getdev.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "hdwwiz.h"
|
|
#include <htmlhelp.h>
|
|
|
|
HMODULE hDevMgr=NULL;
|
|
PDEVICEPROBLEMTEXT pDeviceProblemText = NULL;
|
|
|
|
PTCHAR
|
|
DeviceProblemText(
|
|
DEVNODE DevNode,
|
|
ULONG Status,
|
|
ULONG ProblemNumber
|
|
)
|
|
{
|
|
UINT LenChars, ReqLenChars;
|
|
PTCHAR Buffer=NULL;
|
|
PTCHAR p=NULL;
|
|
TCHAR TempBuffer[MAX_PATH];
|
|
|
|
if (hDevMgr) {
|
|
|
|
if (!pDeviceProblemText) {
|
|
|
|
pDeviceProblemText = (PDEVICEPROBLEMTEXT)GetProcAddress(hDevMgr, "DeviceProblemTextW");
|
|
}
|
|
}
|
|
|
|
if (pDeviceProblemText) {
|
|
|
|
LenChars = (pDeviceProblemText)(NULL,
|
|
DevNode,
|
|
ProblemNumber,
|
|
Buffer,
|
|
0
|
|
);
|
|
|
|
if (!LenChars) {
|
|
|
|
goto DPTExitCleanup;
|
|
}
|
|
|
|
LenChars++; // one extra for terminating NULL
|
|
|
|
Buffer = LocalAlloc(LPTR, LenChars*sizeof(TCHAR));
|
|
|
|
if (!Buffer) {
|
|
|
|
goto DPTExitCleanup;
|
|
}
|
|
|
|
ReqLenChars = (pDeviceProblemText)(NULL,
|
|
DevNode,
|
|
ProblemNumber,
|
|
Buffer,
|
|
LenChars
|
|
);
|
|
|
|
if (!ReqLenChars || ReqLenChars >= LenChars) {
|
|
|
|
LocalFree(Buffer);
|
|
Buffer = NULL;
|
|
}
|
|
|
|
if (Buffer && (Status != 0)) {
|
|
if (Status & DN_WILL_BE_REMOVED) {
|
|
if (LoadString(hHdwWiz,
|
|
IDS_WILL_BE_REMOVED,
|
|
TempBuffer,
|
|
SIZECHARS(TempBuffer)
|
|
)) {
|
|
LenChars += lstrlen(TempBuffer) + 1;
|
|
p = LocalAlloc(LPTR, LenChars*sizeof(TCHAR));
|
|
|
|
if (p) {
|
|
StringCchCopy(p, LenChars, Buffer);
|
|
StringCchCat(p, LenChars, TempBuffer);
|
|
LocalFree(Buffer);
|
|
Buffer = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Status & DN_NEED_RESTART) {
|
|
if (LoadString(hHdwWiz,
|
|
IDS_NEED_RESTART,
|
|
TempBuffer,
|
|
SIZECHARS(TempBuffer)
|
|
)) {
|
|
LenChars += lstrlen(TempBuffer) + 1;
|
|
p = LocalAlloc(LPTR, LenChars*sizeof(TCHAR));
|
|
|
|
if (p) {
|
|
StringCchCopy(p, LenChars, Buffer);
|
|
StringCchCat(p, LenChars, TempBuffer);
|
|
LocalFree(Buffer);
|
|
Buffer = p;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DPTExitCleanup:
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
int CALLBACK
|
|
DeviceListCompare(
|
|
LPARAM lParam1,
|
|
LPARAM lParam2,
|
|
LPARAM lParamSort
|
|
)
|
|
{
|
|
TCHAR ClassName1[MAX_CLASS_NAME_LEN];
|
|
TCHAR ClassName2[MAX_CLASS_NAME_LEN];
|
|
TCHAR Buffer[MAX_PATH];
|
|
GUID ClassGuid1, ClassGuid2;
|
|
BOOL bSpecialClass1 = FALSE, bSpecialClass2 = FALSE;
|
|
ULONG ulLength;
|
|
ULONG Status, Problem1, Problem2;
|
|
|
|
UNREFERENCED_PARAMETER(lParamSort);
|
|
|
|
//
|
|
// Return
|
|
// -1 if the first item should precede the second
|
|
// +1 if the first item should follow the second
|
|
// 0 if they are the same
|
|
//
|
|
|
|
//
|
|
// First check if lParam1 or lParam2 are 0. A 0 lParam means that this
|
|
// is the special 'Add a new hardware device' that goes at the bottom
|
|
// of the list.
|
|
//
|
|
if (lParam1 == 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (lParam2 == 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (CM_Get_DevNode_Status(&Status, &Problem1, (DEVINST)lParam1, 0) != CR_SUCCESS) {
|
|
Problem1 = 0;
|
|
}
|
|
|
|
if (CM_Get_DevNode_Status(&Status, &Problem2, (DEVINST)lParam2, 0) != CR_SUCCESS) {
|
|
Problem2 = 0;
|
|
}
|
|
|
|
//
|
|
// Devices with problems always go at the top of the list. If both devices
|
|
// have problems then we sort by class name.
|
|
//
|
|
if (Problem1 && !Problem2) {
|
|
return -1;
|
|
} else if (!Problem1 && Problem2) {
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// The next check is to put the special device classes above non-special
|
|
// device classes.
|
|
//
|
|
ulLength = sizeof(Buffer);
|
|
if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam1,
|
|
CM_DRP_CLASSGUID,
|
|
NULL,
|
|
Buffer,
|
|
&ulLength,
|
|
0) == CR_SUCCESS) &&
|
|
(ulLength != 0)) {
|
|
|
|
pSetupGuidFromString(Buffer, &ClassGuid1);
|
|
|
|
if (IsEqualGUID(&ClassGuid1, &GUID_DEVCLASS_DISPLAY) ||
|
|
IsEqualGUID(&ClassGuid1, &GUID_DEVCLASS_MEDIA)) {
|
|
//
|
|
// Device 1 is one of the special classes that go at the top of the list.
|
|
//
|
|
bSpecialClass1 = TRUE;
|
|
}
|
|
}
|
|
|
|
ulLength = sizeof(Buffer);
|
|
if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam2,
|
|
CM_DRP_CLASSGUID,
|
|
NULL,
|
|
Buffer,
|
|
&ulLength,
|
|
0) == CR_SUCCESS) &&
|
|
(ulLength != 0)) {
|
|
|
|
pSetupGuidFromString(Buffer, &ClassGuid2);
|
|
|
|
if (IsEqualGUID(&ClassGuid2, &GUID_DEVCLASS_DISPLAY) ||
|
|
IsEqualGUID(&ClassGuid2, &GUID_DEVCLASS_MEDIA)) {
|
|
//
|
|
// Device 2 is one of the special classes that go at the top of the list.
|
|
//
|
|
bSpecialClass2 = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bSpecialClass1 && !bSpecialClass2) {
|
|
return -1;
|
|
} else if (!bSpecialClass1 && bSpecialClass2) {
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// The final check is to sort the items by classes
|
|
//
|
|
ulLength = sizeof(ClassName1);
|
|
if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam1,
|
|
CM_DRP_CLASS,
|
|
NULL,
|
|
ClassName1,
|
|
&ulLength,
|
|
0) != CR_SUCCESS) ||
|
|
(ulLength == 0)) {
|
|
//
|
|
// If we could not get a class name then set it to all Z's so it will
|
|
// get put at the bottom of the list.
|
|
//
|
|
StringCchCopy(ClassName1, SIZECHARS(ClassName1), TEXT("ZZZZZZZZZZ"));;
|
|
}
|
|
|
|
ulLength = sizeof(ClassName2);
|
|
if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam2,
|
|
CM_DRP_CLASS,
|
|
NULL,
|
|
ClassName2,
|
|
&ulLength,
|
|
0) != CR_SUCCESS) ||
|
|
(ulLength == 0)) {
|
|
//
|
|
// If we could not get a class name then set it to all Z's so it will
|
|
// get put at the bottom of the list.
|
|
//
|
|
StringCchCopy(ClassName2, SIZECHARS(ClassName2), TEXT("ZZZZZZZZZZ"));;
|
|
}
|
|
|
|
return lstrcmpi(ClassName1, ClassName2);
|
|
}
|
|
|
|
void
|
|
InsertNoneOfTheseDevices(
|
|
HWND hwndList
|
|
)
|
|
{
|
|
LV_ITEM lviItem;
|
|
TCHAR String[MAX_PATH];
|
|
|
|
LoadString(hHdwWiz, IDS_HDW_NONEDEVICES, String, SIZECHARS(String));
|
|
|
|
lviItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
|
|
lviItem.iSubItem = 0;
|
|
lviItem.lParam = (LPARAM)0;
|
|
lviItem.iItem = 0;
|
|
lviItem.iImage = g_BlankIconIndex;
|
|
lviItem.pszText = String;
|
|
|
|
ListView_InsertItem(hwndList, &lviItem);
|
|
}
|
|
|
|
BOOL
|
|
ProblemDeviceListFilter(
|
|
PHARDWAREWIZ HardwareWiz,
|
|
PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is a callback for the BuildDeviceListView API. It will get called
|
|
for every device and can filter which devices end up getting displayed. If it
|
|
returns FALSE then the given device won't be displayed. If it returns TRUE then
|
|
the device will be displayed.
|
|
|
|
Currently we will filter out all system devices from the problem devices list since
|
|
they cluter up the list view and it would be very rare that a user would come to
|
|
Add Hardware to add a system device.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(HardwareWiz);
|
|
|
|
//
|
|
// If this is a system class device then filter it out of the list by
|
|
// returning FALSE.
|
|
//
|
|
if (IsEqualGUID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_SYSTEM)) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
INT_PTR CALLBACK
|
|
HdwProbListDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
standard stuff.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
INT_PTR
|
|
|
|
--*/
|
|
|
|
{
|
|
PHARDWAREWIZ HardwareWiz;
|
|
|
|
if (message == WM_INITDIALOG) {
|
|
|
|
LV_COLUMN lvcCol;
|
|
LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
|
|
|
|
HardwareWiz = (PHARDWAREWIZ) lppsp->lParam;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
|
|
HardwareWiz->hwndProbList = GetDlgItem(hDlg, IDC_HDWPROBLIST);
|
|
|
|
//
|
|
// Insert columns for listview.
|
|
// 0 == device name
|
|
//
|
|
|
|
lvcCol.mask = LVCF_WIDTH | LVCF_SUBITEM;
|
|
|
|
lvcCol.iSubItem = 0;
|
|
ListView_InsertColumn(HardwareWiz->hwndProbList, 0, &lvcCol);
|
|
|
|
SendMessage(HardwareWiz->hwndProbList,
|
|
LVM_SETEXTENDEDLISTVIEWSTYLE,
|
|
LVS_EX_FULLROWSELECT,
|
|
LVS_EX_FULLROWSELECT
|
|
);
|
|
|
|
ListView_SetExtendedListViewStyle(HardwareWiz->hwndProbList, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// retrieve private data from window long (stored there during WM_INITDIALOG)
|
|
//
|
|
HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
switch (message) {
|
|
|
|
case WM_DESTROY:
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
break;
|
|
|
|
case WM_NOTIFY: {
|
|
|
|
NMHDR FAR *pnmhdr = (NMHDR FAR *)lParam;
|
|
|
|
switch (pnmhdr->code) {
|
|
|
|
case PSN_SETACTIVE: {
|
|
|
|
DWORD DevicesDetected;
|
|
HWND hwndProbList;
|
|
HWND hwndParentDlg;
|
|
LVITEM lvItem;
|
|
|
|
hwndParentDlg = GetParent(hDlg);
|
|
|
|
HardwareWiz->PrevPage = IDD_ADDDEVICE_PROBLIST;
|
|
|
|
//
|
|
// initialize the list view, we do this on each setactive
|
|
// since a new class may have been installed or the problem
|
|
// device list may change as we go back and forth between pages.
|
|
//
|
|
hwndProbList = HardwareWiz->hwndProbList;
|
|
|
|
SendMessage(hwndProbList, WM_SETREDRAW, FALSE, 0L);
|
|
ListView_DeleteAllItems(hwndProbList);
|
|
|
|
if (HardwareWiz->ClassImageList.cbSize) {
|
|
|
|
ListView_SetImageList(hwndProbList,
|
|
HardwareWiz->ClassImageList.ImageList,
|
|
LVSIL_SMALL
|
|
);
|
|
}
|
|
|
|
//
|
|
// Next put all of the devices into the list
|
|
//
|
|
DevicesDetected = 0;
|
|
BuildDeviceListView(HardwareWiz,
|
|
HardwareWiz->hwndProbList,
|
|
FALSE,
|
|
HardwareWiz->ProblemDevInst,
|
|
&DevicesDetected,
|
|
ProblemDeviceListFilter
|
|
);
|
|
|
|
InsertNoneOfTheseDevices(HardwareWiz->hwndProbList);
|
|
|
|
//
|
|
// Sort the list
|
|
//
|
|
ListView_SortItems(HardwareWiz->hwndProbList,
|
|
(PFNLVCOMPARE)DeviceListCompare,
|
|
NULL
|
|
);
|
|
|
|
lvItem.mask = LVIF_PARAM;
|
|
lvItem.iSubItem = 0;
|
|
lvItem.iItem = ListView_GetNextItem(HardwareWiz->hwndProbList, -1, LVNI_SELECTED);
|
|
|
|
//
|
|
// select the first item in the list if nothing else was selected
|
|
//
|
|
if (lvItem.iItem == -1) {
|
|
|
|
ListView_SetItemState(hwndProbList,
|
|
0,
|
|
LVIS_FOCUSED,
|
|
LVIS_FOCUSED
|
|
);
|
|
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK);
|
|
|
|
} else {
|
|
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
|
|
}
|
|
|
|
ListView_EnsureVisible(hwndProbList, lvItem.iItem, FALSE);
|
|
ListView_SetColumnWidth(hwndProbList, 0, LVSCW_AUTOSIZE_USEHEADER);
|
|
|
|
SendMessage(hwndProbList, WM_SETREDRAW, TRUE, 0L);
|
|
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZNEXT: {
|
|
|
|
LVITEM lvItem;
|
|
|
|
lvItem.mask = LVIF_PARAM;
|
|
lvItem.iSubItem = 0;
|
|
lvItem.iItem = ListView_GetNextItem(HardwareWiz->hwndProbList, -1, LVNI_SELECTED);
|
|
|
|
if (lvItem.iItem != -1) {
|
|
|
|
ListView_GetItem(HardwareWiz->hwndProbList, &lvItem);
|
|
|
|
HardwareWiz->ProblemDevInst = (DEVNODE)lvItem.lParam;
|
|
|
|
} else {
|
|
|
|
HardwareWiz->ProblemDevInst = 0;
|
|
}
|
|
|
|
//
|
|
// If the HardwareWiz->ProblemDevInst is 0 then the user selected none of the items
|
|
// so we will move on to detection
|
|
//
|
|
if (HardwareWiz->ProblemDevInst == 0) {
|
|
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, IDD_ADDDEVICE_ASKDETECT);
|
|
|
|
} else {
|
|
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, IDD_ADDDEVICE_PROBLIST_FINISH);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZFINISH:
|
|
break;
|
|
|
|
|
|
case PSN_WIZBACK:
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, IDD_ADDDEVICE_CONNECTED);
|
|
break;
|
|
|
|
case NM_DBLCLK:
|
|
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
case LVN_ITEMCHANGED:
|
|
if (ListView_GetSelectedCount(HardwareWiz->hwndProbList) == 0) {
|
|
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
|
|
} else {
|
|
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
HdwWizPropagateMessage(hDlg, message, wParam, lParam);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
INT_PTR CALLBACK
|
|
HdwProbListFinishDlgProc(
|
|
HWND hDlg,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
INT_PTR
|
|
|
|
--*/
|
|
|
|
{
|
|
PHARDWAREWIZ HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
|
|
if (wMsg == WM_INITDIALOG) {
|
|
LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
|
|
|
|
HardwareWiz = (PHARDWAREWIZ)lppsp->lParam;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
|
|
SetWindowFont(GetDlgItem(hDlg, IDC_HDWNAME), HardwareWiz->hfontTextBigBold, TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
switch (wMsg) {
|
|
case WM_DESTROY:
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
break;
|
|
|
|
case WM_NOTIFY: {
|
|
NMHDR FAR *pnmhdr = (NMHDR FAR *)lParam;
|
|
|
|
switch (pnmhdr->code) {
|
|
case PSN_SETACTIVE:
|
|
{
|
|
PTCHAR FriendlyName;
|
|
PTCHAR ProblemText;
|
|
ULONG Status, Problem;
|
|
|
|
FriendlyName = BuildFriendlyName(HardwareWiz->ProblemDevInst);
|
|
if (FriendlyName) {
|
|
|
|
SetDlgItemText(hDlg, IDC_HDW_DESCRIPTION, FriendlyName);
|
|
LocalFree(FriendlyName);
|
|
}
|
|
|
|
Status = Problem = 0;
|
|
CM_Get_DevNode_Status(&Status,
|
|
&Problem,
|
|
HardwareWiz->ProblemDevInst,
|
|
0
|
|
);
|
|
|
|
ProblemText = DeviceProblemText(HardwareWiz->ProblemDevInst,
|
|
Status,
|
|
Problem
|
|
);
|
|
|
|
if (ProblemText) {
|
|
SetDlgItemText(hDlg, IDC_PROBLEM_DESC, ProblemText);
|
|
LocalFree(ProblemText);
|
|
}
|
|
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZFINISH:
|
|
HardwareWiz->RunTroubleShooter = TRUE;
|
|
break;
|
|
|
|
case PSN_WIZBACK:
|
|
SetDlgMsgResult(hDlg, wMsg, IDD_ADDDEVICE_PROBLIST);
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|