mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 08:08:38 +00:00
0182dcd71b
- Make sure the DWLP_* values are correct on _WIN64 - Don't use the DWL_* constants, they are not portable. Enforce this by removing them entirely from winuser.h - Make sure Get/SetWindowLong*Ptr* is used and pointers are not truncated to LONG
1114 lines
37 KiB
C++
1114 lines
37 KiB
C++
/*
|
|
* ReactOS Device Manager Applet
|
|
* Copyright (C) 2004 - 2005 ReactOS Team
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*
|
|
* PROJECT: ReactOS devmgr.dll
|
|
* FILE: lib/devmgr/hwpage.c
|
|
* PURPOSE: ReactOS Device Manager
|
|
* PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
|
|
* UPDATE HISTORY:
|
|
* 04-04-2004 Created
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include "properties.h"
|
|
#include "resource.h"
|
|
|
|
|
|
typedef struct _HWDEVINFO
|
|
{
|
|
struct _HWCLASSDEVINFO *ClassDevInfo;
|
|
SP_DEVINFO_DATA DevInfoData;
|
|
BOOL HideDevice;
|
|
} HWDEVINFO, *PHWDEVINFO;
|
|
|
|
typedef struct _HWCLASSDEVINFO
|
|
{
|
|
GUID Guid;
|
|
HDEVINFO hDevInfo;
|
|
INT ImageIndex;
|
|
INT ItemCount;
|
|
PHWDEVINFO HwDevInfo;
|
|
} HWCLASSDEVINFO, *PHWCLASSDEVINFO;
|
|
|
|
typedef struct _HARDWARE_PAGE_DATA
|
|
{
|
|
HWND hWnd;
|
|
HWND hWndDevList;
|
|
HINSTANCE hComCtl32; /* only save this to keep track of the references */
|
|
INT DevListViewHeight;
|
|
SP_CLASSIMAGELIST_DATA ClassImageListData;
|
|
HWPAGE_DISPLAYMODE DisplayMode;
|
|
|
|
/* parent window subclass info */
|
|
WNDPROC ParentOldWndProc;
|
|
HWND hWndParent;
|
|
|
|
UINT NumberOfGuids;
|
|
HWCLASSDEVINFO ClassDevInfo[1];
|
|
/* struct may be dynamically expanded here! */
|
|
} HARDWARE_PAGE_DATA, *PHARDWARE_PAGE_DATA;
|
|
|
|
#define CX_TYPECOLUMN_WIDTH 80
|
|
|
|
static VOID
|
|
InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
|
|
{
|
|
LVCOLUMN lvc;
|
|
RECT rcClient;
|
|
WCHAR szColName[255];
|
|
int iCol = 0;
|
|
|
|
/* set the list view style */
|
|
(void)ListView_SetExtendedListViewStyle(hpd->hWndDevList,
|
|
LVS_EX_FULLROWSELECT);
|
|
|
|
/* set the list view image list */
|
|
if (hpd->ClassImageListData.ImageList != NULL)
|
|
{
|
|
(void)ListView_SetImageList(hpd->hWndDevList,
|
|
hpd->ClassImageListData.ImageList,
|
|
LVSIL_SMALL);
|
|
}
|
|
|
|
GetClientRect(hpd->hWndDevList,
|
|
&rcClient);
|
|
|
|
/* add the list view columns */
|
|
lvc.mask = LVCF_TEXT | LVCF_WIDTH;
|
|
lvc.fmt = LVCFMT_LEFT;
|
|
lvc.pszText = szColName;
|
|
|
|
if (LoadString(hDllInstance,
|
|
IDS_NAME,
|
|
szColName,
|
|
sizeof(szColName) / sizeof(szColName[0])))
|
|
{
|
|
lvc.cx = rcClient.right - CX_TYPECOLUMN_WIDTH -
|
|
GetSystemMetrics(SM_CXVSCROLL);
|
|
(void)ListView_InsertColumn(hpd->hWndDevList,
|
|
iCol++,
|
|
&lvc);
|
|
}
|
|
if (LoadString(hDllInstance,
|
|
IDS_TYPE,
|
|
szColName,
|
|
sizeof(szColName) / sizeof(szColName[0])))
|
|
{
|
|
lvc.cx = CX_TYPECOLUMN_WIDTH;
|
|
(void)ListView_InsertColumn(hpd->hWndDevList,
|
|
iCol++,
|
|
&lvc);
|
|
}
|
|
}
|
|
|
|
|
|
static BOOL
|
|
DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd)
|
|
{
|
|
PHWDEVINFO HwDevInfo;
|
|
SP_DEVINFO_DATA DevInfoData;
|
|
BOOL Ret = FALSE;
|
|
|
|
HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
|
|
if (HwDevInfo != NULL)
|
|
{
|
|
/* make a copy of the SP_DEVINFO_DATA structure on the stack, it may
|
|
become invalid in case the devices are updated */
|
|
DevInfoData = HwDevInfo->DevInfoData;
|
|
|
|
/* display the advanced properties */
|
|
Ret = DisplayDeviceAdvancedProperties(hpd->hWnd,
|
|
NULL,
|
|
HwDevInfo->ClassDevInfo->hDevInfo,
|
|
&DevInfoData,
|
|
hpd->hComCtl32,
|
|
NULL,
|
|
0) != -1;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
static VOID
|
|
UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd)
|
|
{
|
|
PHWDEVINFO HwDevInfo;
|
|
HWND hBtnTroubleShoot, hBtnProperties;
|
|
|
|
hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
|
|
IDC_TROUBLESHOOT);
|
|
hBtnProperties = GetDlgItem(hpd->hWnd,
|
|
IDC_PROPERTIES);
|
|
|
|
HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
|
|
if (HwDevInfo != NULL)
|
|
{
|
|
/* update static controls */
|
|
WCHAR szBuffer[256];
|
|
LPWSTR szFormatted = NULL;
|
|
|
|
/* get the manufacturer string */
|
|
if (GetDeviceManufacturerString(HwDevInfo->ClassDevInfo->hDevInfo,
|
|
&HwDevInfo->DevInfoData,
|
|
szBuffer,
|
|
sizeof(szBuffer) / sizeof(szBuffer[0])) &&
|
|
LoadAndFormatString(hDllInstance,
|
|
IDS_MANUFACTURER,
|
|
&szFormatted,
|
|
szBuffer) != 0)
|
|
{
|
|
SetDlgItemText(hpd->hWnd,
|
|
IDC_MANUFACTURER,
|
|
szFormatted);
|
|
LocalFree((HLOCAL)szFormatted);
|
|
}
|
|
|
|
/* get the location string */
|
|
if (GetDeviceLocationString(HwDevInfo->ClassDevInfo->hDevInfo,
|
|
&HwDevInfo->DevInfoData,
|
|
0,
|
|
szBuffer,
|
|
sizeof(szBuffer) / sizeof(szBuffer[0])) &&
|
|
LoadAndFormatString(hDllInstance,
|
|
IDS_LOCATION,
|
|
&szFormatted,
|
|
szBuffer) != 0)
|
|
{
|
|
SetDlgItemText(hpd->hWnd,
|
|
IDC_LOCATION,
|
|
szFormatted);
|
|
LocalFree((HLOCAL)szFormatted);
|
|
}
|
|
|
|
if (GetDeviceStatusString(HwDevInfo->DevInfoData.DevInst,
|
|
NULL,
|
|
szBuffer,
|
|
sizeof(szBuffer) / sizeof(szBuffer[0])) &&
|
|
LoadAndFormatString(hDllInstance,
|
|
IDS_STATUS,
|
|
&szFormatted,
|
|
szBuffer) != 0)
|
|
{
|
|
SetDlgItemText(hpd->hWnd,
|
|
IDC_STATUS,
|
|
szFormatted);
|
|
LocalFree((HLOCAL)szFormatted);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* clear static controls */
|
|
SetDlgItemText(hpd->hWnd,
|
|
IDC_MANUFACTURER,
|
|
NULL);
|
|
SetDlgItemText(hpd->hWnd,
|
|
IDC_LOCATION,
|
|
NULL);
|
|
SetDlgItemText(hpd->hWnd,
|
|
IDC_STATUS,
|
|
NULL);
|
|
}
|
|
|
|
EnableWindow(hBtnTroubleShoot,
|
|
HwDevInfo != NULL);
|
|
EnableWindow(hBtnProperties,
|
|
HwDevInfo != NULL);
|
|
}
|
|
|
|
|
|
static VOID
|
|
FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
|
|
{
|
|
PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
|
|
|
|
ClassDevInfo = hpd->ClassDevInfo;
|
|
LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
|
|
|
|
/* free the device info set handles and structures */
|
|
while (ClassDevInfo != LastClassDevInfo)
|
|
{
|
|
if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
|
|
{
|
|
SetupDiDestroyDeviceInfoList(ClassDevInfo->hDevInfo);
|
|
ClassDevInfo->hDevInfo = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
ClassDevInfo->ItemCount = 0;
|
|
ClassDevInfo->ImageIndex = 0;
|
|
|
|
if (ClassDevInfo->HwDevInfo != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
ClassDevInfo->HwDevInfo);
|
|
ClassDevInfo->HwDevInfo = NULL;
|
|
}
|
|
|
|
ClassDevInfo++;
|
|
}
|
|
}
|
|
|
|
|
|
static VOID
|
|
BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd)
|
|
{
|
|
PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
|
|
SP_DEVINFO_DATA DevInfoData;
|
|
|
|
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
|
|
ClassDevInfo = hpd->ClassDevInfo;
|
|
LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
|
|
|
|
while (ClassDevInfo != LastClassDevInfo)
|
|
{
|
|
ClassDevInfo->ImageIndex = -1;
|
|
|
|
/* open a class device handle for the GUID we're processing */
|
|
ClassDevInfo->hDevInfo = SetupDiGetClassDevs(&ClassDevInfo->Guid,
|
|
NULL,
|
|
hpd->hWnd,
|
|
DIGCF_PRESENT | DIGCF_PROFILE);
|
|
if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD MemberIndex = 0;
|
|
|
|
SetupDiGetClassImageIndex(&hpd->ClassImageListData,
|
|
&ClassDevInfo->Guid,
|
|
&ClassDevInfo->ImageIndex);
|
|
|
|
/* enumerate all devices in the class */
|
|
while (SetupDiEnumDeviceInfo(ClassDevInfo->hDevInfo,
|
|
MemberIndex++,
|
|
&DevInfoData))
|
|
{
|
|
BOOL HideDevice = FALSE;
|
|
|
|
if (ClassDevInfo->HwDevInfo != NULL)
|
|
{
|
|
PHWDEVINFO HwNewDevInfo = (PHWDEVINFO)HeapReAlloc(GetProcessHeap(),
|
|
0,
|
|
ClassDevInfo->HwDevInfo,
|
|
(ClassDevInfo->ItemCount + 1) *
|
|
sizeof(HWDEVINFO));
|
|
if (HwNewDevInfo != NULL)
|
|
{
|
|
ClassDevInfo->HwDevInfo = HwNewDevInfo;
|
|
}
|
|
else
|
|
{
|
|
ERR("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
|
|
ClassDevInfo->ItemCount + 1);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ClassDevInfo->HwDevInfo = (PHWDEVINFO)HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
sizeof(HWDEVINFO));
|
|
if (ClassDevInfo->HwDevInfo == NULL)
|
|
{
|
|
ERR("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Find out if the device should be hidden by default */
|
|
IsDeviceHidden(DevInfoData.DevInst,
|
|
NULL,
|
|
&HideDevice);
|
|
|
|
/* save all information for the current device */
|
|
ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].ClassDevInfo = ClassDevInfo;
|
|
ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].DevInfoData = DevInfoData;
|
|
ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount++].HideDevice = HideDevice;
|
|
}
|
|
}
|
|
|
|
ClassDevInfo++;
|
|
}
|
|
}
|
|
|
|
|
|
static BOOL
|
|
DeviceIdMatch(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN LPCWSTR lpDeviceId)
|
|
{
|
|
DWORD DevIdLen;
|
|
LPWSTR lpQueriedDeviceId;
|
|
BOOL Ret = FALSE;
|
|
|
|
if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL,
|
|
0,
|
|
&DevIdLen) &&
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
if (DevIdLen == wcslen(lpDeviceId) + 1)
|
|
{
|
|
lpQueriedDeviceId = (LPWSTR)HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
DevIdLen * sizeof(WCHAR));
|
|
if (lpQueriedDeviceId != NULL)
|
|
{
|
|
if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
lpQueriedDeviceId,
|
|
DevIdLen,
|
|
NULL))
|
|
{
|
|
Ret = (wcscmp(lpDeviceId,
|
|
lpQueriedDeviceId) == 0);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpQueriedDeviceId);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
static VOID
|
|
FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd,
|
|
IN LPCWSTR lpSelectDeviceId OPTIONAL,
|
|
IN GUID *SelectedClassGuid OPTIONAL)
|
|
{
|
|
PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
|
|
PHWDEVINFO HwDevInfo, LastHwDevInfo;
|
|
WCHAR szBuffer[255];
|
|
BOOL SelectedInClass;
|
|
INT ItemCount = 0;
|
|
|
|
BuildDevicesList(hpd);
|
|
|
|
ClassDevInfo = hpd->ClassDevInfo;
|
|
LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
|
|
|
|
while (ClassDevInfo != LastClassDevInfo)
|
|
{
|
|
if (ClassDevInfo->HwDevInfo != NULL)
|
|
{
|
|
HwDevInfo = ClassDevInfo->HwDevInfo;
|
|
LastHwDevInfo = HwDevInfo + ClassDevInfo->ItemCount;
|
|
|
|
SelectedInClass = (SelectedClassGuid != NULL &&
|
|
IsEqualGUID(*SelectedClassGuid,
|
|
ClassDevInfo->Guid));
|
|
while (HwDevInfo != LastHwDevInfo)
|
|
{
|
|
INT iItem;
|
|
LVITEM li = {0};
|
|
|
|
/* get the device name */
|
|
if (!HwDevInfo->HideDevice &&
|
|
GetDeviceDescriptionString(ClassDevInfo->hDevInfo,
|
|
&HwDevInfo->DevInfoData,
|
|
szBuffer,
|
|
sizeof(szBuffer) / sizeof(szBuffer[0])))
|
|
{
|
|
li.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT | LVIF_IMAGE;
|
|
li.iItem = ItemCount;
|
|
if ((ItemCount == 0 && lpSelectDeviceId == NULL) ||
|
|
(SelectedInClass &&
|
|
DeviceIdMatch(ClassDevInfo->hDevInfo,
|
|
&HwDevInfo->DevInfoData,
|
|
lpSelectDeviceId)))
|
|
{
|
|
li.state = LVIS_SELECTED;
|
|
}
|
|
li.stateMask = LVIS_SELECTED;
|
|
li.pszText = szBuffer;
|
|
li.iImage = ClassDevInfo->ImageIndex;
|
|
li.lParam = (LPARAM)HwDevInfo;
|
|
|
|
iItem = ListView_InsertItem(hpd->hWndDevList,
|
|
&li);
|
|
if (iItem != -1)
|
|
{
|
|
ItemCount++;
|
|
|
|
/* get the device type for the second column */
|
|
if (GetDeviceTypeString(&HwDevInfo->DevInfoData,
|
|
szBuffer,
|
|
sizeof(szBuffer) / sizeof(szBuffer[0])))
|
|
{
|
|
li.mask = LVIF_TEXT;
|
|
li.iItem = iItem;
|
|
li.iSubItem = 1;
|
|
|
|
(void)ListView_SetItem(hpd->hWndDevList,
|
|
&li);
|
|
}
|
|
}
|
|
}
|
|
|
|
HwDevInfo++;
|
|
}
|
|
}
|
|
|
|
ClassDevInfo++;
|
|
}
|
|
|
|
/* update the controls */
|
|
UpdateControlStates(hpd);
|
|
}
|
|
|
|
|
|
static VOID
|
|
UpdateDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd)
|
|
{
|
|
PHWDEVINFO HwDevInfo;
|
|
GUID SelectedClassGuid = {0};
|
|
LPWSTR lpDeviceId = NULL;
|
|
|
|
/* if a device currently is selected, remember the device id so we can
|
|
select the device after the update if still present */
|
|
HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
|
|
if (HwDevInfo != NULL)
|
|
{
|
|
DWORD DevIdLen;
|
|
if (!SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo,
|
|
&HwDevInfo->DevInfoData,
|
|
NULL,
|
|
0,
|
|
&DevIdLen) &&
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
SelectedClassGuid = HwDevInfo->DevInfoData.ClassGuid;
|
|
lpDeviceId = (LPWSTR)HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
DevIdLen * sizeof(WCHAR));
|
|
if (lpDeviceId != NULL &&
|
|
!SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo,
|
|
&HwDevInfo->DevInfoData,
|
|
lpDeviceId,
|
|
DevIdLen,
|
|
NULL))
|
|
{
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpDeviceId);
|
|
lpDeviceId = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* clear the devices list view control */
|
|
(void)ListView_DeleteAllItems(hpd->hWndDevList);
|
|
|
|
/* free the device list */
|
|
FreeDevicesList(hpd);
|
|
|
|
/* build rebuild the device list and fill the list box again */
|
|
FillDevicesListViewControl(hpd,
|
|
lpDeviceId,
|
|
(lpDeviceId != NULL ?
|
|
&SelectedClassGuid :
|
|
NULL));
|
|
|
|
if (lpDeviceId != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpDeviceId);
|
|
}
|
|
}
|
|
|
|
|
|
static LRESULT
|
|
CALLBACK
|
|
ParentSubWndProc(IN HWND hwnd,
|
|
IN UINT uMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
PHARDWARE_PAGE_DATA hpd;
|
|
|
|
hpd = (PHARDWARE_PAGE_DATA)GetProp(hwnd,
|
|
L"DevMgrSubClassInfo");
|
|
if (hpd != NULL)
|
|
{
|
|
if (uMsg == WM_SIZE)
|
|
{
|
|
/* resize the hardware page */
|
|
SetWindowPos(hpd->hWnd,
|
|
NULL,
|
|
0,
|
|
0,
|
|
LOWORD(lParam),
|
|
HIWORD(lParam),
|
|
SWP_NOZORDER);
|
|
}
|
|
else if (uMsg == WM_DEVICECHANGE && IsWindowVisible(hpd->hWnd))
|
|
{
|
|
/* forward a WM_DEVICECHANGE message to the hardware
|
|
page which wouldn't get the message itself as it is
|
|
a child window */
|
|
SendMessage(hpd->hWnd,
|
|
WM_DEVICECHANGE,
|
|
wParam,
|
|
lParam);
|
|
}
|
|
|
|
/* pass the message the the old window proc */
|
|
return CallWindowProc(hpd->ParentOldWndProc,
|
|
hwnd,
|
|
uMsg,
|
|
wParam,
|
|
lParam);
|
|
}
|
|
else
|
|
{
|
|
/* this is not a good idea if the subclassed window was an ansi
|
|
window, but we failed finding out the previous window proc
|
|
so we can't use CallWindowProc. This should rarely - if ever -
|
|
happen. */
|
|
|
|
return DefWindowProc(hwnd,
|
|
uMsg,
|
|
wParam,
|
|
lParam);
|
|
}
|
|
}
|
|
|
|
|
|
static VOID
|
|
HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd,
|
|
IN INT cx,
|
|
IN INT cy)
|
|
{
|
|
HDWP dwp;
|
|
HWND hControl, hButton;
|
|
INT Width, x, y;
|
|
RECT rc, rcButton;
|
|
POINT pt = {0};
|
|
POINT ptMargin = {0};
|
|
POINT ptMarginGroup = {0};
|
|
|
|
/* use left margin of the IDC_DEVICES label as the right
|
|
margin of all controls outside the group box */
|
|
hControl = GetDlgItem(hpd->hWnd,
|
|
IDC_DEVICES);
|
|
GetWindowRect(hControl,
|
|
&rc);
|
|
MapWindowPoints(hControl,
|
|
hpd->hWnd,
|
|
&ptMargin,
|
|
1);
|
|
|
|
Width = cx - (2 * ptMargin.x);
|
|
|
|
if ((dwp = BeginDeferWindowPos(8)))
|
|
{
|
|
/* rc already has the window rect of IDC_DEVICES! */
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hControl,
|
|
NULL,
|
|
0,
|
|
0,
|
|
Width,
|
|
rc.bottom - rc.top,
|
|
SWP_NOMOVE | SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* resize the devices list view control */
|
|
GetWindowRect(hpd->hWndDevList,
|
|
&rc);
|
|
MapWindowPoints(hpd->hWndDevList,
|
|
hpd->hWnd,
|
|
&pt,
|
|
1);
|
|
y = pt.y + hpd->DevListViewHeight + ptMargin.y;
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hpd->hWndDevList,
|
|
NULL,
|
|
0,
|
|
0,
|
|
Width,
|
|
hpd->DevListViewHeight,
|
|
SWP_NOMOVE | SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* resize the group box control */
|
|
hControl = GetDlgItem(hpd->hWnd,
|
|
IDC_PROPERTIESGROUP);
|
|
GetWindowRect(hControl,
|
|
&rc);
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hControl,
|
|
NULL,
|
|
ptMargin.x,
|
|
y,
|
|
Width,
|
|
cy - y - ptMargin.y,
|
|
SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* use left margin of the IDC_MANUFACTURER label as the right
|
|
margin of all controls inside the group box */
|
|
hControl = GetDlgItem(hpd->hWnd,
|
|
IDC_MANUFACTURER);
|
|
GetWindowRect(hControl,
|
|
&rc);
|
|
MapWindowPoints(hControl,
|
|
hpd->hWnd,
|
|
&ptMarginGroup,
|
|
1);
|
|
|
|
ptMarginGroup.y = ptMargin.y * 2;
|
|
Width = cx - (2 * ptMarginGroup.x);
|
|
y += ptMarginGroup.y;
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hControl,
|
|
NULL,
|
|
ptMarginGroup.x,
|
|
y,
|
|
Width,
|
|
rc.bottom - rc.top,
|
|
SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
y += rc.bottom - rc.top + (ptMargin.y / 2);
|
|
|
|
/* resize the IDC_LOCATION label */
|
|
hControl = GetDlgItem(hpd->hWnd,
|
|
IDC_LOCATION);
|
|
GetWindowRect(hControl,
|
|
&rc);
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hControl,
|
|
NULL,
|
|
ptMarginGroup.x,
|
|
y,
|
|
Width,
|
|
rc.bottom - rc.top,
|
|
SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
y += rc.bottom - rc.top + (ptMargin.y / 2);
|
|
|
|
/* measure the size of the buttons */
|
|
hButton = GetDlgItem(hpd->hWnd,
|
|
IDC_PROPERTIES);
|
|
GetWindowRect(hButton,
|
|
&rcButton);
|
|
|
|
/* resize the IDC_STATUS label */
|
|
hControl = GetDlgItem(hpd->hWnd,
|
|
IDC_STATUS);
|
|
GetWindowRect(hControl,
|
|
&rc);
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hControl,
|
|
NULL,
|
|
ptMarginGroup.x,
|
|
y,
|
|
Width,
|
|
cy - y - (3 * ptMargin.y) -
|
|
(rcButton.bottom - rcButton.top),
|
|
SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* move the IDC_PROPERTIES button */
|
|
y = cy - (2 * ptMargin.y) - (rcButton.bottom - rcButton.top);
|
|
x = cx - ptMarginGroup.x - (rcButton.right - rcButton.left);
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hButton,
|
|
NULL,
|
|
x,
|
|
y,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* move the IDC_TROUBLESHOOT button */
|
|
hButton = GetDlgItem(hpd->hWnd,
|
|
IDC_TROUBLESHOOT);
|
|
GetWindowRect(hButton,
|
|
&rcButton);
|
|
x -= (ptMargin.x / 2) + (rcButton.right - rcButton.left);
|
|
if (!(dwp = DeferWindowPos(dwp,
|
|
hButton,
|
|
NULL,
|
|
x,
|
|
y,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
EndDeferWindowPos(dwp);
|
|
}
|
|
}
|
|
|
|
|
|
static VOID
|
|
EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd,
|
|
BOOL Enable)
|
|
{
|
|
HWND hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
|
|
IDC_TROUBLESHOOT);
|
|
|
|
ShowWindow(hBtnTroubleShoot,
|
|
Enable ? SW_SHOW : SW_HIDE);
|
|
}
|
|
|
|
|
|
static INT_PTR
|
|
CALLBACK
|
|
HardwareDlgProc(IN HWND hwndDlg,
|
|
IN UINT uMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
PHARDWARE_PAGE_DATA hpd;
|
|
INT_PTR Ret = FALSE;
|
|
|
|
hpd = (PHARDWARE_PAGE_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
|
|
|
|
if (hpd != NULL || uMsg == WM_INITDIALOG)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_NOTIFY:
|
|
{
|
|
NMHDR *pnmh = (NMHDR*)lParam;
|
|
if (pnmh->hwndFrom == hpd->hWndDevList)
|
|
{
|
|
switch (pnmh->code)
|
|
{
|
|
case LVN_ITEMCHANGED:
|
|
{
|
|
LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
|
|
|
|
if ((pnmv->uChanged & LVIF_STATE) &&
|
|
((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
|
|
(pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
|
|
{
|
|
UpdateControlStates(hpd);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case NM_DBLCLK:
|
|
{
|
|
DisplaySelectedDeviceProperties(hpd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_TROUBLESHOOT:
|
|
{
|
|
/* FIXME - start the help using the command in the window text */
|
|
break;
|
|
}
|
|
|
|
case IDC_PROPERTIES:
|
|
{
|
|
DisplaySelectedDeviceProperties(hpd);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_SIZE:
|
|
HardwareDlgResize(hpd,
|
|
(INT)LOWORD(lParam),
|
|
(INT)HIWORD(lParam));
|
|
break;
|
|
|
|
case WM_SETTEXT:
|
|
{
|
|
LPCWSTR szWndText = (LPCWSTR)lParam;
|
|
EnableTroubleShoot(hpd,
|
|
(szWndText != NULL && szWndText[0] != L'\0'));
|
|
break;
|
|
}
|
|
|
|
case WM_DEVICECHANGE:
|
|
{
|
|
/* FIXME - don't call UpdateDevicesListViewControl for all events */
|
|
UpdateDevicesListViewControl(hpd);
|
|
Ret = TRUE;
|
|
break;
|
|
}
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
hpd = (PHARDWARE_PAGE_DATA)lParam;
|
|
if (hpd != NULL)
|
|
{
|
|
HWND hWndParent;
|
|
|
|
hpd->hWnd = hwndDlg;
|
|
SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)hpd);
|
|
|
|
hpd->ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
|
|
|
|
SetupDiGetClassImageList(&hpd->ClassImageListData);
|
|
|
|
/* calculate the size of the devices list view control */
|
|
hpd->hWndDevList = GetDlgItem(hwndDlg,
|
|
IDC_LV_DEVICES);
|
|
if (hpd->hWndDevList != NULL)
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(hpd->hWndDevList,
|
|
&rcClient);
|
|
hpd->DevListViewHeight = rcClient.bottom;
|
|
|
|
if (hpd->DisplayMode == HWPD_LARGELIST)
|
|
{
|
|
hpd->DevListViewHeight = (hpd->DevListViewHeight * 3) / 2;
|
|
}
|
|
}
|
|
|
|
/* subclass the parent window */
|
|
hWndParent = GetAncestor(hwndDlg,
|
|
GA_PARENT);
|
|
if (hWndParent != NULL)
|
|
{
|
|
RECT rcClient;
|
|
|
|
if (GetClientRect(hWndParent,
|
|
&rcClient) &&
|
|
SetWindowPos(hwndDlg,
|
|
NULL,
|
|
0,
|
|
0,
|
|
rcClient.right,
|
|
rcClient.bottom,
|
|
SWP_NOZORDER))
|
|
{
|
|
/* subclass the parent window. This is not safe
|
|
if the parent window belongs to another thread! */
|
|
hpd->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
|
|
GWLP_WNDPROC,
|
|
(LONG_PTR)ParentSubWndProc);
|
|
|
|
if (hpd->ParentOldWndProc != NULL &&
|
|
SetProp(hWndParent,
|
|
L"DevMgrSubClassInfo",
|
|
(HANDLE)hpd))
|
|
{
|
|
hpd->hWndParent = hWndParent;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* initialize the devices list view control */
|
|
InitializeDevicesList(hpd);
|
|
|
|
/* fill the devices list view control */
|
|
FillDevicesListViewControl(hpd,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* decide whether to show or hide the troubleshoot button */
|
|
EnableTroubleShoot(hpd,
|
|
GetWindowTextLength(hwndDlg) != 0);
|
|
}
|
|
Ret = TRUE;
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
/* zero hpd pointer in window data, because it can be used later (WM_DESTROY has not to be last message) */
|
|
SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)NULL);
|
|
|
|
/* free devices list */
|
|
FreeDevicesList(hpd);
|
|
|
|
/* restore the old window proc of the subclassed parent window */
|
|
if (hpd->hWndParent != NULL && hpd->ParentOldWndProc != NULL)
|
|
{
|
|
SetWindowLongPtr(hpd->hWndParent,
|
|
GWLP_WNDPROC,
|
|
(LONG_PTR)hpd->ParentOldWndProc);
|
|
}
|
|
|
|
if (hpd->ClassImageListData.ImageList != NULL)
|
|
{
|
|
SetupDiDestroyClassImageList(&hpd->ClassImageListData);
|
|
}
|
|
|
|
/* free the reference to comctl32 */
|
|
FreeLibrary(hpd->hComCtl32);
|
|
hpd->hComCtl32 = NULL;
|
|
|
|
/* free the allocated resources */
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
hpd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* NAME EXPORTED
|
|
* DeviceCreateHardwarePageEx
|
|
*
|
|
* DESCRIPTION
|
|
* Creates a hardware page
|
|
*
|
|
* ARGUMENTS
|
|
* hWndParent: Handle to the parent window
|
|
* lpGuids: An array of guids of devices that are to be listed
|
|
* uNumberOfGuids: Numbers of guids in the Guids array
|
|
* DisplayMode: Sets the size of the device list view control
|
|
*
|
|
* RETURN VALUE
|
|
* Returns the handle of the hardware page window that has been created or
|
|
* NULL if it failed.
|
|
*
|
|
* @implemented
|
|
*/
|
|
HWND
|
|
WINAPI
|
|
DeviceCreateHardwarePageEx(IN HWND hWndParent,
|
|
IN LPGUID lpGuids,
|
|
IN UINT uNumberOfGuids,
|
|
IN HWPAGE_DISPLAYMODE DisplayMode)
|
|
{
|
|
PHARDWARE_PAGE_DATA hpd;
|
|
|
|
/* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
|
|
zeroed because the initialization code assumes that in
|
|
failure cases! */
|
|
hpd = (PHARDWARE_PAGE_DATA)HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
FIELD_OFFSET(HARDWARE_PAGE_DATA,
|
|
ClassDevInfo[uNumberOfGuids]));
|
|
if (hpd != NULL)
|
|
{
|
|
HWND hWnd;
|
|
UINT i;
|
|
|
|
hpd->DisplayMode = ((DisplayMode > HWPD_MAX) ? HWPD_STANDARDLIST : DisplayMode);
|
|
|
|
/* initialize the HARDWARE_PAGE_DATA structure */
|
|
hpd->NumberOfGuids = uNumberOfGuids;
|
|
for (i = 0;
|
|
i < uNumberOfGuids;
|
|
i++)
|
|
{
|
|
hpd->ClassDevInfo[i].hDevInfo = INVALID_HANDLE_VALUE;
|
|
hpd->ClassDevInfo[i].Guid = lpGuids[i];
|
|
}
|
|
|
|
/* load comctl32.dll dynamically */
|
|
hpd->hComCtl32 = LoadAndInitComctl32();
|
|
if (hpd->hComCtl32 == NULL)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
/* create the dialog */
|
|
hWnd = CreateDialogParam(hDllInstance,
|
|
MAKEINTRESOURCE(IDD_HARDWARE),
|
|
hWndParent,
|
|
HardwareDlgProc,
|
|
(LPARAM)hpd);
|
|
if (hWnd != NULL)
|
|
{
|
|
return hWnd;
|
|
}
|
|
else
|
|
{
|
|
Cleanup:
|
|
/* oops, something went wrong... */
|
|
if (hpd->hComCtl32 != NULL)
|
|
{
|
|
FreeLibrary(hpd->hComCtl32);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
hpd);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* NAME EXPORTED
|
|
* DeviceCreateHardwarePage
|
|
*
|
|
* DESCRIPTION
|
|
* Creates a hardware page
|
|
*
|
|
* ARGUMENTS
|
|
* hWndParent: Handle to the parent window
|
|
* lpGuid: Guid of the device
|
|
*
|
|
* RETURN VALUE
|
|
* Returns the handle of the hardware page window that has been created or
|
|
* NULL if it failed.
|
|
*
|
|
* @implemented
|
|
*/
|
|
HWND
|
|
WINAPI
|
|
DeviceCreateHardwarePage(IN HWND hWndParent,
|
|
IN LPGUID lpGuid)
|
|
{
|
|
return DeviceCreateHardwarePageEx(hWndParent,
|
|
lpGuid,
|
|
1,
|
|
HWPD_LARGELIST);
|
|
}
|