|
Guest
|
Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE
Hello,
I'm working on an application that acts on WM_DEVICECHANGE messages with
wParam value == DBT_DEVICEARRIVAL (indicating the device has either just been
plugged into the system or has just been enabled in Device Manager), examines
the device ID, and if it matches a particular wildcard value, it disables the
device using calls to SetupDiSetClassInstallParams and
SetupDiCallClassInstaller with a control.context value == DICS_DISABLE.
Here's the phenomena I'm seeing:
1) In the above functionality, the call to SetupDiCallClassInstaller takes
approximately 30 seconds to execute, after which time the device gets
disabled successfully.
2) If I write similar code that responds to WM_DEVICECHANGE /
DBT_DEVICEREMOVECOMPLETE messages (when a device is disabled) by calling the
code to enable the device, it works fine and immediately.
3) If I have a button in my application that when pressed just calls these
functions to enable or disable a device, the code works absolutely fine and
the device state is changed immediately (for all of my tests, I'm running
Device Manager alongside my application so I can monitor whether the device
has a red cross on it, indicating a disabled state, or not, indicating an
enabled state).
My question then is - why does it take so long to disable a device in
response to it being added / enabled?
Is there an alternative approach that would give better results?
I wondered if it might be a timing problem, e.g. I'm trying to disable the
device too soon after it's been added / enabled, and it isn't fully
initialised yet. So I tried adding a Sleep into the code, even up to 20
seconds, but it made no difference.
The code I use for the actual enabling / disabling has been lifted from the
DDK Devcon sample application (which exposes all of Device Manager's
functionality via a command line interface), a combination of the cmdEnable,
cmdDisable and ControlCallback functions:
----------
bool CDeviceControlHelper::EnableDevice(const HDEVINFO Devs,
const PSP_DEVINFO_DATA DevInfo,
const bool& bEnable,
tstring& sRetMessage)
{
GenericContext context;
TCHAR strEnable[80];
TCHAR strDisable[80];
TCHAR strReboot[80];
TCHAR strFail[80];
if (bEnable)
{
if (!LoadString(NULL,IDS_ENABLED,strEnable,ARRAYSIZE( strEnable)))
{
return false;
}
if (!LoadString(NULL,IDS_ENABLED_REBOOT,strReboot,ARR AYSIZE(strReboot)))
{
return false;
}
if (!LoadString(NULL,IDS_ENABLE_FAILED,strFail,ARRAYS IZE(strFail)))
{
return false;
}
context.control = DICS_ENABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE
context.strSuccess = strEnable;
}
else
{
if (!LoadString(NULL,IDS_DISABLED,strDisable,ARRAYSIZ E(strDisable)))
{
return false;
}
if (!LoadString(NULL,IDS_DISABLED_REBOOT,strReboot,AR RAYSIZE(strReboot)))
{
return false;
}
if (!LoadString(NULL,IDS_DISABLE_FAILED,strFail,ARRAY SIZE(strFail)))
{
return false;
}
context.control = DICS_DISABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE
context.strSuccess = strDisable;
}
context.reboot = FALSE;
context.count = 0;
context.strReboot = strReboot;
context.strFail = strFail;
// ControlCallback function body
SP_PROPCHANGE_PARAMS pcp;
SP_DEVINSTALL_PARAMS devParams;
switch(context.control)
{
case DICS_ENABLE:
//
// enable both on global and config-specific profile
// do global first and see if that succeeded in enabling the
device
// (global enable doesn't mark reboot required if device is still
// disabled on current config whereas vice-versa isn't true)
//
pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
pcp.StateChange = context.control;
pcp.Scope = DICS_FLAG_GLOBAL;
pcp.HwProfile = 0;
//
// don't worry if this fails, we'll get an error when we try
config-
// specific.
if (SetupDiSetClassInstallParams(Devs, DevInfo,
&pcp.ClassInstallHeader, sizeof(pcp)))
{
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,Devs, DevInfo);
}
//
// now enable on config-specific
//
pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
pcp.StateChange = context.control;
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
pcp.HwProfile = 0;
break;
default:
//
// operate on config-specific profile
//
pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
pcp.StateChange = context.control;
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
pcp.HwProfile = 0;
break;
}
if (!SetupDiSetClassInstallParams(Devs, DevInfo, &pcp.ClassInstallHeader,
sizeof(pcp)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,Devs ,DevInfo))
{
//
// failed to invoke DIF_PROPERTYCHANGE
//
DumpDeviceWithInfo(Devs,DevInfo,context.strFail);
}
else
{
//
// see if device needs reboot
//
devParams.cbSize = sizeof(devParams);
if (SetupDiGetDeviceInstallParams(Devs,DevInfo,&devPa rams) &&
(devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)))
{
DumpDeviceWithInfo(Devs,DevInfo,context.strReboot) ;
context.reboot = TRUE;
}
else
{
//
// appears to have succeeded
//
DumpDeviceWithInfo(Devs,DevInfo,context.strSuccess );
}
context.count++;
}
bool bRet = false;
if (bEnable)
{
if (!context.count)
{
sRetMessage.LoadString(IDS_MSG_ENABLE_TAIL_NONE);
}
else if (!context.reboot)
{
sRetMessage.Format(IDS_MSG_ENABLE_TAIL, context.count);
bRet = true;
}
else
{
sRetMessage.Format(IDS_MSG_ENABLE_TAIL_REBOOT, context.count);
}
}
else
{
if (!context.count)
{
sRetMessage.LoadString(IDS_MSG_DISABLE_TAIL_NONE);
}
else if (!context.reboot)
{
sRetMessage.Format(IDS_MSG_DISABLE_TAIL, context.count);
bRet = true;
}
else
{
sRetMessage.Format(IDS_MSG_DISABLE_TAIL_REBOOT, context.count);
}
}
return bRet;
}
----------
Many thanks in advance for any help / advice that anyone can offer in
response to this problem.
JP
|