mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 11:56:26 +00:00
4f0b8d3db0
svn path=/branches/ntvdm/; revision=59241
1150 lines
32 KiB
C
1150 lines
32 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/misc.c
|
|
* PURPOSE: ReactOS Device Manager
|
|
* PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
|
|
* UPDATE HISTORY:
|
|
* 2005/11/24 Created
|
|
*/
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
HINSTANCE hDllInstance = NULL;
|
|
|
|
|
|
INT
|
|
LengthOfStrResource(IN HINSTANCE hInst,
|
|
IN UINT uID)
|
|
{
|
|
HRSRC hrSrc;
|
|
HGLOBAL hRes;
|
|
LPWSTR lpName, lpStr;
|
|
|
|
if (hInst == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/* There are always blocks of 16 strings */
|
|
lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
|
|
|
|
/* Find the string table block */
|
|
if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
|
|
(hRes = LoadResource(hInst, hrSrc)) &&
|
|
(lpStr = LockResource(hRes)))
|
|
{
|
|
UINT x;
|
|
|
|
/* Find the string we're looking for */
|
|
uID &= 0xF; /* position in the block, same as % 16 */
|
|
for (x = 0; x < uID; x++)
|
|
{
|
|
lpStr += (*lpStr) + 1;
|
|
}
|
|
|
|
/* Found the string */
|
|
return (int)(*lpStr);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
static INT
|
|
AllocAndLoadString(OUT LPWSTR *lpTarget,
|
|
IN HINSTANCE hInst,
|
|
IN UINT uID)
|
|
{
|
|
INT ln;
|
|
|
|
ln = LengthOfStrResource(hInst,
|
|
uID);
|
|
if (ln++ > 0)
|
|
{
|
|
(*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
|
|
ln * sizeof(WCHAR));
|
|
if ((*lpTarget) != NULL)
|
|
{
|
|
INT Ret;
|
|
if (!(Ret = LoadStringW(hInst, uID, *lpTarget, ln)))
|
|
{
|
|
LocalFree((HLOCAL)(*lpTarget));
|
|
}
|
|
return Ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static INT
|
|
AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
|
|
IN HINSTANCE hInst,
|
|
IN UINT *uID,
|
|
IN UINT nIDs)
|
|
{
|
|
INT ln = 0;
|
|
UINT i;
|
|
|
|
for (i = 0;
|
|
i != nIDs;
|
|
i++)
|
|
{
|
|
ln += LengthOfStrResource(hInst,
|
|
uID[i]);
|
|
}
|
|
|
|
if (ln != 0)
|
|
{
|
|
(*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
|
|
(ln + 1) * sizeof(WCHAR));
|
|
if ((*lpTarget) != NULL)
|
|
{
|
|
LPWSTR s = *lpTarget;
|
|
INT Ret = 0;
|
|
|
|
for (i = 0;
|
|
i != nIDs;
|
|
i++)
|
|
{
|
|
if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
|
|
{
|
|
LocalFree((HLOCAL)(*lpTarget));
|
|
return 0;
|
|
}
|
|
|
|
s += Ret;
|
|
}
|
|
|
|
return s - *lpTarget;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
LoadAndFormatString(IN HINSTANCE hInstance,
|
|
IN UINT uID,
|
|
OUT LPWSTR *lpTarget,
|
|
...)
|
|
{
|
|
DWORD Ret = 0;
|
|
LPWSTR lpFormat;
|
|
va_list lArgs;
|
|
|
|
if (AllocAndLoadString(&lpFormat,
|
|
hInstance,
|
|
uID) != 0)
|
|
{
|
|
va_start(lArgs, lpTarget);
|
|
/* let's use FormatMessage to format it because it has the ability to allocate
|
|
memory automatically */
|
|
Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
|
lpFormat,
|
|
0,
|
|
0,
|
|
(LPWSTR)lpTarget,
|
|
0,
|
|
&lArgs);
|
|
va_end(lArgs);
|
|
|
|
LocalFree((HLOCAL)lpFormat);
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
DWORD
|
|
LoadAndFormatStringsCat(IN HINSTANCE hInstance,
|
|
IN UINT *uID,
|
|
IN UINT nIDs,
|
|
OUT LPWSTR *lpTarget,
|
|
...)
|
|
{
|
|
DWORD Ret = 0;
|
|
LPWSTR lpFormat;
|
|
va_list lArgs;
|
|
|
|
if (AllocAndLoadStringsCat(&lpFormat,
|
|
hInstance,
|
|
uID,
|
|
nIDs) != 0)
|
|
{
|
|
va_start(lArgs, lpTarget);
|
|
/* let's use FormatMessage to format it because it has the ability to allocate
|
|
memory automatically */
|
|
Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
|
lpFormat,
|
|
0,
|
|
0,
|
|
(LPWSTR)lpTarget,
|
|
0,
|
|
&lArgs);
|
|
va_end(lArgs);
|
|
|
|
LocalFree((HLOCAL)lpFormat);
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
LPARAM
|
|
ListViewGetSelectedItemData(IN HWND hwnd)
|
|
{
|
|
int Index;
|
|
|
|
Index = ListView_GetNextItem(hwnd,
|
|
-1,
|
|
LVNI_SELECTED);
|
|
if (Index != -1)
|
|
{
|
|
LVITEM li;
|
|
|
|
li.mask = LVIF_PARAM;
|
|
li.iItem = Index;
|
|
li.iSubItem = 0;
|
|
|
|
if (ListView_GetItem(hwnd,
|
|
&li))
|
|
{
|
|
return li.lParam;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
|
|
IN UINT uCodePage)
|
|
{
|
|
LPWSTR lpUnicodeStr;
|
|
INT nLength;
|
|
|
|
nLength = MultiByteToWideChar(uCodePage,
|
|
0,
|
|
lpMultiByteStr,
|
|
-1,
|
|
NULL,
|
|
0);
|
|
if (nLength == 0)
|
|
return NULL;
|
|
|
|
lpUnicodeStr = HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
nLength * sizeof(WCHAR));
|
|
if (lpUnicodeStr == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
if (!MultiByteToWideChar(uCodePage,
|
|
0,
|
|
lpMultiByteStr,
|
|
nLength,
|
|
lpUnicodeStr,
|
|
nLength))
|
|
{
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpUnicodeStr);
|
|
return NULL;
|
|
}
|
|
|
|
return lpUnicodeStr;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
DWORD RegDataType;
|
|
BOOL Ret = FALSE;
|
|
|
|
if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_MFG,
|
|
&RegDataType,
|
|
(PBYTE)szBuffer,
|
|
BufferSize * sizeof(WCHAR),
|
|
NULL) ||
|
|
RegDataType != REG_SZ)
|
|
{
|
|
szBuffer[0] = L'\0';
|
|
if (LoadString(hDllInstance,
|
|
IDS_UNKNOWN,
|
|
szBuffer,
|
|
BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* FIXME - check string for NULL termination! */
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDeviceLocationString(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DEVINST dnParentDevInst OPTIONAL,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
DWORD RegDataType;
|
|
ULONG DataSize;
|
|
CONFIGRET cRet;
|
|
LPWSTR szFormatted;
|
|
HKEY hKey;
|
|
DWORD dwSize, dwType;
|
|
BOOL Ret = FALSE;
|
|
|
|
DataSize = BufferSize * sizeof(WCHAR);
|
|
szBuffer[0] = L'\0';
|
|
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_QUERY_VALUE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* query the LocationInformationOverride value */
|
|
dwSize = BufferSize;
|
|
if (RegQueryValueEx(hKey,
|
|
L"LocationInformationOverride",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)szBuffer,
|
|
&dwSize) == ERROR_SUCCESS &&
|
|
dwType == REG_SZ &&
|
|
szBuffer[0] != L'\0')
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
szBuffer[0] = L'\0';
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
|
|
if (!Ret)
|
|
{
|
|
if (dnParentDevInst != 0)
|
|
{
|
|
/* query the parent node name */
|
|
if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
|
|
CM_DRP_DEVICEDESC,
|
|
&RegDataType,
|
|
szBuffer,
|
|
&DataSize,
|
|
0) == CR_SUCCESS &&
|
|
RegDataType == REG_SZ &&
|
|
LoadAndFormatString(hDllInstance,
|
|
IDS_DEVONPARENT,
|
|
&szFormatted,
|
|
szBuffer) != 0)
|
|
{
|
|
wcsncpy(szBuffer,
|
|
szFormatted,
|
|
BufferSize - 1);
|
|
szBuffer[BufferSize - 1] = L'\0';
|
|
LocalFree((HLOCAL)szFormatted);
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
else if (DeviceInfoData->DevInst != 0)
|
|
{
|
|
cRet = CM_Get_DevNode_Registry_Property(DeviceInfoData->DevInst,
|
|
CM_DRP_LOCATION_INFORMATION,
|
|
&RegDataType,
|
|
szBuffer,
|
|
&DataSize,
|
|
0);
|
|
if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
|
|
{
|
|
/* FIXME - check string for NULL termination! */
|
|
Ret = TRUE;
|
|
}
|
|
|
|
if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
|
|
{
|
|
/* convert the string to an integer value and create a
|
|
formatted string */
|
|
ULONG ulLocation = (ULONG)wcstoul(szBuffer,
|
|
NULL,
|
|
10);
|
|
if (LoadAndFormatString(hDllInstance,
|
|
IDS_LOCATIONSTR,
|
|
&szFormatted,
|
|
ulLocation,
|
|
szBuffer) != 0)
|
|
{
|
|
wcsncpy(szBuffer,
|
|
szFormatted,
|
|
BufferSize - 1);
|
|
szBuffer[BufferSize - 1] = L'\0';
|
|
LocalFree((HLOCAL)szFormatted);
|
|
}
|
|
else
|
|
Ret = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Ret &&
|
|
LoadString(hDllInstance,
|
|
IDS_UNKNOWN,
|
|
szBuffer,
|
|
BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDeviceStatusString(IN DEVINST DevInst,
|
|
IN HMACHINE hMachine,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
CONFIGRET cr;
|
|
ULONG Status, ProblemNumber;
|
|
UINT MessageId = IDS_UNKNOWN;
|
|
BOOL Ret = FALSE;
|
|
|
|
szBuffer[0] = L'\0';
|
|
cr = CM_Get_DevNode_Status_Ex(&Status,
|
|
&ProblemNumber,
|
|
DevInst,
|
|
0,
|
|
hMachine);
|
|
if (cr == CR_SUCCESS)
|
|
{
|
|
if (Status & DN_HAS_PROBLEM)
|
|
{
|
|
UINT uRet;
|
|
|
|
uRet = DeviceProblemText(hMachine,
|
|
DevInst,
|
|
ProblemNumber,
|
|
szBuffer,
|
|
(BufferSize != 0 ? BufferSize : BufferSize - 1));
|
|
|
|
Ret = (uRet != 0 && uRet < BufferSize);
|
|
}
|
|
else
|
|
{
|
|
if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
|
|
{
|
|
MessageId = IDS_NODRIVERLOADED;
|
|
}
|
|
else
|
|
{
|
|
MessageId = IDS_DEV_NO_PROBLEM;
|
|
}
|
|
|
|
goto GeneralMessage;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GeneralMessage:
|
|
if (LoadString(hDllInstance,
|
|
MessageId,
|
|
szBuffer,
|
|
(int)BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDriverProviderString(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwSize, dwType;
|
|
BOOL Ret = FALSE;
|
|
|
|
szBuffer[0] = L'\0';
|
|
|
|
/* get driver provider, date and version */
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_QUERY_VALUE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* query the driver provider */
|
|
dwSize = BufferSize;
|
|
if (RegQueryValueEx(hKey,
|
|
REGSTR_VAL_PROVIDER_NAME,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)szBuffer,
|
|
&dwSize) == ERROR_SUCCESS &&
|
|
dwType == REG_SZ &&
|
|
szBuffer[0] != L'\0')
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
szBuffer[0] = L'\0';
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (szBuffer[0] == L'\0')
|
|
{
|
|
/* unable to query the information */
|
|
if (LoadString(hDllInstance,
|
|
IDS_UNKNOWN,
|
|
szBuffer,
|
|
BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDriverVersionString(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwSize, dwType;
|
|
BOOL Ret = FALSE;
|
|
|
|
szBuffer[0] = L'\0';
|
|
|
|
/* get driver provider, date and version */
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_QUERY_VALUE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* query the driver provider */
|
|
dwSize = BufferSize;
|
|
if (RegQueryValueEx(hKey,
|
|
L"DriverVersion",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)szBuffer,
|
|
&dwSize) == ERROR_SUCCESS &&
|
|
dwType == REG_SZ &&
|
|
szBuffer[0] != L'\0')
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
szBuffer[0] = L'\0';
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (szBuffer[0] == L'\0')
|
|
{
|
|
/* unable to query the information */
|
|
if (LoadString(hDllInstance,
|
|
IDS_NOTAVAILABLE,
|
|
szBuffer,
|
|
BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
BOOL
|
|
GetDriverDateString(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
HKEY hKey;
|
|
FILETIME DriverDate;
|
|
SYSTEMTIME SystemTime, LocalTime;
|
|
DWORD dwSize, dwType;
|
|
BOOL Ret = FALSE;
|
|
|
|
szBuffer[0] = L'\0';
|
|
|
|
/* get driver provider, date and version */
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_QUERY_VALUE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* query the driver provider */
|
|
dwSize = sizeof(FILETIME);
|
|
if (RegQueryValueEx(hKey,
|
|
L"DriverDateData",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&DriverDate,
|
|
&dwSize) == ERROR_SUCCESS &&
|
|
dwType == REG_BINARY &&
|
|
dwSize == sizeof(FILETIME) &&
|
|
FileTimeToSystemTime(&DriverDate,
|
|
&SystemTime) &&
|
|
SystemTimeToTzSpecificLocalTime(NULL,
|
|
&SystemTime,
|
|
&LocalTime) &&
|
|
GetDateFormat(LOCALE_USER_DEFAULT,
|
|
DATE_SHORTDATE,
|
|
&LocalTime,
|
|
NULL,
|
|
szBuffer,
|
|
BufferSize) != 0)
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (!Ret)
|
|
{
|
|
/* unable to query the information */
|
|
if (LoadString(hDllInstance,
|
|
IDS_NOTAVAILABLE,
|
|
szBuffer,
|
|
BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsDeviceHidden(IN DEVINST DevInst,
|
|
IN HMACHINE hMachine,
|
|
OUT BOOL *IsHidden)
|
|
{
|
|
CONFIGRET cr;
|
|
ULONG Status, ProblemNumber;
|
|
BOOL Ret = FALSE;
|
|
|
|
cr = CM_Get_DevNode_Status_Ex(&Status,
|
|
&ProblemNumber,
|
|
DevInst,
|
|
0,
|
|
hMachine);
|
|
if (cr == CR_SUCCESS)
|
|
{
|
|
*IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CanDisableDevice(IN DEVINST DevInst,
|
|
IN HMACHINE hMachine,
|
|
OUT BOOL *CanDisable)
|
|
{
|
|
CONFIGRET cr;
|
|
ULONG Status, ProblemNumber;
|
|
BOOL Ret = FALSE;
|
|
|
|
cr = CM_Get_DevNode_Status_Ex(&Status,
|
|
&ProblemNumber,
|
|
DevInst,
|
|
0,
|
|
hMachine);
|
|
if (cr == CR_SUCCESS)
|
|
{
|
|
*CanDisable = ((Status & DN_DISABLEABLE) != 0);
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDeviceStarted(IN DEVINST DevInst,
|
|
IN HMACHINE hMachine,
|
|
OUT BOOL *IsStarted)
|
|
{
|
|
CONFIGRET cr;
|
|
ULONG Status, ProblemNumber;
|
|
BOOL Ret = FALSE;
|
|
|
|
cr = CM_Get_DevNode_Status_Ex(&Status,
|
|
&ProblemNumber,
|
|
DevInst,
|
|
0,
|
|
hMachine);
|
|
if (cr == CR_SUCCESS)
|
|
{
|
|
*IsStarted = ((Status & DN_STARTED) != 0);
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDriverInstalled(IN DEVINST DevInst,
|
|
IN HMACHINE hMachine,
|
|
OUT BOOL *Installed)
|
|
{
|
|
CONFIGRET cr;
|
|
ULONG Status, ProblemNumber;
|
|
BOOL Ret = FALSE;
|
|
|
|
cr = CM_Get_DevNode_Status_Ex(&Status,
|
|
&ProblemNumber,
|
|
DevInst,
|
|
0,
|
|
hMachine);
|
|
if (cr == CR_SUCCESS)
|
|
{
|
|
*Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
|
|
(Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnableDevice(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
|
|
IN BOOL bEnable,
|
|
IN DWORD HardwareProfile OPTIONAL,
|
|
OUT BOOL *bNeedReboot OPTIONAL)
|
|
{
|
|
SP_PROPCHANGE_PARAMS pcp;
|
|
SP_DEVINSTALL_PARAMS dp;
|
|
DWORD LastErr;
|
|
BOOL Ret = FALSE;
|
|
|
|
pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
|
|
pcp.HwProfile = HardwareProfile;
|
|
|
|
if (bEnable)
|
|
{
|
|
/* try to enable the device on the global profile */
|
|
pcp.StateChange = DICS_ENABLE;
|
|
pcp.Scope = DICS_FLAG_GLOBAL;
|
|
|
|
/* ignore errors */
|
|
LastErr = GetLastError();
|
|
if (SetupDiSetClassInstallParams(DeviceInfoSet,
|
|
DevInfoData,
|
|
&pcp.ClassInstallHeader,
|
|
sizeof(SP_PROPCHANGE_PARAMS)))
|
|
{
|
|
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
|
|
DeviceInfoSet,
|
|
DevInfoData);
|
|
}
|
|
SetLastError(LastErr);
|
|
}
|
|
|
|
/* try config-specific */
|
|
pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
|
|
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
|
|
|
|
if (SetupDiSetClassInstallParams(DeviceInfoSet,
|
|
DevInfoData,
|
|
&pcp.ClassInstallHeader,
|
|
sizeof(SP_PROPCHANGE_PARAMS)) &&
|
|
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
|
|
DeviceInfoSet,
|
|
DevInfoData))
|
|
{
|
|
dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
|
|
DevInfoData,
|
|
&dp))
|
|
{
|
|
if (bNeedReboot != NULL)
|
|
{
|
|
*bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
|
|
}
|
|
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
BOOL Ret = FALSE;
|
|
|
|
if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
|
|
szBuffer,
|
|
BufferSize,
|
|
NULL))
|
|
{
|
|
szBuffer[0] = L'\0';
|
|
if (LoadString(hDllInstance,
|
|
IDS_UNKNOWN,
|
|
szBuffer,
|
|
BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* FIXME - check string for NULL termination! */
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT LPWSTR szBuffer,
|
|
IN DWORD BufferSize)
|
|
{
|
|
DWORD RegDataType;
|
|
BOOL Ret = FALSE;
|
|
|
|
if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_FRIENDLYNAME,
|
|
&RegDataType,
|
|
(PBYTE)szBuffer,
|
|
BufferSize * sizeof(WCHAR),
|
|
NULL) ||
|
|
SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_DEVICEDESC,
|
|
&RegDataType,
|
|
(PBYTE)szBuffer,
|
|
BufferSize * sizeof(WCHAR),
|
|
NULL)) &&
|
|
RegDataType == REG_SZ)
|
|
{
|
|
/* FIXME - check string for NULL termination! */
|
|
Ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
szBuffer[0] = L'\0';
|
|
if (LoadString(hDllInstance,
|
|
IDS_UNKNOWNDEVICE,
|
|
szBuffer,
|
|
BufferSize))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindCurrentDriver(IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT PSP_DRVINFO_DATA DriverInfoData)
|
|
{
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
SP_DEVINSTALL_PARAMS InstallParams = {0};
|
|
SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = {0};
|
|
WCHAR InfPath[MAX_PATH];
|
|
WCHAR InfSection[LINE_LEN];
|
|
DWORD dwType, dwLength;
|
|
DWORD i = 0;
|
|
LONG rc;
|
|
BOOL Ret = FALSE;
|
|
|
|
/* Steps to find the right driver:
|
|
* 1) Get the device install parameters
|
|
* 2) Open the driver registry key
|
|
* 3) Read the .inf file name
|
|
* 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name
|
|
* 5) Build class driver list
|
|
* 6) Read inf section and inf section extension from registry
|
|
* 7) Enumerate drivers
|
|
* 8) Find the one who is in the same section as current driver?
|
|
*/
|
|
|
|
/* 1) Get the install params */
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (!SetupDiGetDeviceInstallParams(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&InstallParams))
|
|
{
|
|
DPRINT1("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
#ifdef DI_FLAGSEX_INSTALLEDDRIVER
|
|
InstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
|
|
if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&InstallParams))
|
|
{
|
|
if (SetupDiBuildDriverInfoList(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDIT_CLASSDRIVER) &&
|
|
SetupDiEnumDriverInfo(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDIT_CLASSDRIVER,
|
|
0,
|
|
DriverInfoData))
|
|
{
|
|
Ret = TRUE;
|
|
}
|
|
|
|
goto Cleanup;
|
|
}
|
|
InstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
|
|
#endif
|
|
|
|
/* 2) Open the driver registry key */
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_QUERY_VALUE);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
DPRINT1("SetupDiOpenDevRegKey() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
/* 3) Read the .inf file name */
|
|
dwLength = (sizeof(InfPath) / sizeof(InfPath[0])) - 1;
|
|
rc = RegQueryValueEx(hKey,
|
|
REGSTR_VAL_INFPATH,
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)InfPath,
|
|
&dwLength);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
DPRINT1("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
else if (dwType != REG_SZ)
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
DPRINT1("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
|
|
goto Cleanup;
|
|
}
|
|
InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
|
|
|
|
/* 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name */
|
|
InstallParams.Flags |= DI_ENUMSINGLEINF;
|
|
InstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
|
|
wcscpy(InstallParams.DriverPath, InfPath);
|
|
if (!SetupDiSetDeviceInstallParams(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&InstallParams))
|
|
{
|
|
DPRINT1("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
/* 5) Build class driver list */
|
|
if (!SetupDiBuildDriverInfoList(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDIT_CLASSDRIVER))
|
|
{
|
|
DPRINT1("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
/* 6) Read inf section and from registry */
|
|
dwLength = (sizeof(InfSection) / sizeof(InfSection[0])) - 1;
|
|
rc = RegQueryValueEx(hKey,
|
|
REGSTR_VAL_INFSECTION,
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)InfSection,
|
|
&dwLength);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
DPRINT1("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
else if (dwType != REG_SZ)
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
DPRINT1("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
|
|
goto Cleanup;
|
|
}
|
|
InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
|
|
|
|
/* 7) Enumerate drivers */
|
|
DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
|
|
DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
|
|
while (SetupDiEnumDriverInfo(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDIT_CLASSDRIVER,
|
|
i,
|
|
DriverInfoData))
|
|
{
|
|
/* 8) Find the one who is in the same section as current driver */
|
|
if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DriverInfoData,
|
|
&DriverInfoDetailData,
|
|
DriverInfoDetailData.cbSize,
|
|
NULL) &&
|
|
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
DPRINT1("SetupDiGetDriverInfoDetail() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
if (!wcsicmp(DriverInfoDetailData.SectionName,
|
|
InfSection) != 0)
|
|
{
|
|
/* We have found the right driver */
|
|
Ret = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
if (GetLastError() != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
DPRINT1("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
|
|
|
Cleanup:
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
RegCloseKey(hKey);
|
|
return Ret;
|
|
}
|
|
|
|
|
|
HINSTANCE
|
|
LoadAndInitComctl32(VOID)
|
|
{
|
|
typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
|
|
PINITCOMMONCONTROLS pInitCommonControls;
|
|
HINSTANCE hComCtl32;
|
|
|
|
hComCtl32 = LoadLibrary(L"comctl32.dll");
|
|
if (hComCtl32 != NULL)
|
|
{
|
|
/* initialize the common controls */
|
|
pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
|
|
"InitCommonControls");
|
|
if (pInitCommonControls == NULL)
|
|
{
|
|
FreeLibrary(hComCtl32);
|
|
return NULL;
|
|
}
|
|
|
|
pInitCommonControls();
|
|
}
|
|
|
|
return hComCtl32;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllMain(IN HINSTANCE hinstDLL,
|
|
IN DWORD dwReason,
|
|
IN LPVOID lpvReserved)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls(hinstDLL);
|
|
hDllInstance = hinstDLL;
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|