Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE msg

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,ARRAYSIZE(strReboot)))
{
return false;
}
if (!LoadString(NULL,IDS_ENABLE_FAILED,strFail,ARRAYSIZE(strFail)))
{
return false;
}

context.control = DICS_ENABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE
context.strSuccess = strEnable;
}
else
{
if (!LoadString(NULL,IDS_DISABLED,strDisable,ARRAYSIZE(strDisable)))
{
return false;
}
if (!LoadString(NULL,IDS_DISABLED_REBOOT,strReboot,ARRAYSIZE(strReboot)))
{
return false;
}
if (!LoadString(NULL,IDS_DISABLE_FAILED,strFail,ARRAYSIZE(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,&devParams) &&
(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.

HP

Years before I wrote a small app which helps me to reload driver under development after a change. It simply disables all devices and reenables them when driver binary is updated. I encountered the same behaviour; disabling devices using SetupDi APIs was very slow. Always, not only under conditions you describe but it was at w2k and things could change since then. Finally, I found another function which is much faster: CM_Disable_DevNode(). You can try if something changes in your case; if not, there is probably a different problem (non quite initialized device stack as you presumed). Please note I can’t recommend to use this function in production code as it is marked obsolete in docs and probably doesn’t have expected side effects (coinstaller calls?) SetupDi functions have.

(I wonder if at least one person on the world fully understands Setup API :slight_smile:

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]


From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of HP[SMTP:xxxxx@gmail.com]
Reply To: Windows System Software Devs Interest List
Sent: Monday, October 24, 2005 6:06 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE msg

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,ARRAYSIZE(strReboot)))
{
return false;>
}
if (!LoadString(NULL,IDS_ENABLE_FAILED,strFail,ARRAYSIZE(strFail)))
{
return false;
}

context.control = DICS_ENABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE
context.strSuccess = strEnable;
}
else
{
if (!LoadString(NULL,IDS_DISABLED,strDisable,ARRAYSIZE(strDisable)))
{
return false;
}
if (!LoadString(NULL,IDS_DISABLED_REBOOT,strReboot,ARRAYSIZE(strReboot)))
{
return false;
}
if (!LoadString(NULL,IDS_DISABLE_FAILED,strFail,ARRAYSIZE(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,&devParams) &&
(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.

HP


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

Thanks for the feedback - I’ve looked for information on
CM_Disable_DevNode, and it says everywhere that it must no longer be
used - ho hum!

The interesting thing I’ve seen when using the SetupDi APIs is that
it’s very fast as long as I’m not acting directly in response to a
WM_DEVICECHANGE message - that’s when it’s very slow for some reason.

Following on from my earlier message, I’ve found something that helps
with the 30 second delay problem. Instead of calling the
SetupDiSetClassInstallParams / SetupDiCallClassInstaller functionality
directly from the WM_DEVICECHANGE / DBT_DEVICEARRIVAL case, I now set
a variable containing the device id to indicate that disabling is
required. I’ve set up a timer to fire every 5 seconds, and in the
WM_TIMER case, I call the SetupDiSetClassInstallParams /
SetupDiCallClassInstaller functionality. The disabling takes place
immediately upon this code being called. I’m not sure why this
approach helps, but it does.

My changes have improved the responsiveness, but something else that I
see occasionally is that when I have sent a request to disable a
device, the device still looks enabled (no red cross through it) in
Device Manager and is accessible ? yet the right-click context menu
for the item in Device Manager shows an ?Enabled? option, giving the
impression that the device is disabled. This confusion seems to
remain until the computer is restarted.
Does anyone have an idea how to get around this, so that the state
changes in Device Manager and no restart is required?

Interestingly, I saw a similar phenomenon when I set the timer to a
shorter period, e.g. 1 second, - i.e. the device looked enabled in
Device Manager but it was still accessible and the context menu for it
showed an “Enable” option implying that it’s been disabled. It’s
almost as though the disabling had been “half-done” somehow.

I’d be very grateful if anyone has any ideas about the above behaviour
and possible ways of dealing with it, thanks again,

HP

> ----------
> From:
xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com]
on behalf of Michal Vodicka[SMTP:xxxxx@upek.com]
Reply To: Windows System Software Devs Interest List
Sent: Monday, October 24, 2005 22:15:06
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Help disabling a device using SetupDiXXX fns after
WM_DEVICECHANGE msg

Years before I wrote a small app which helps me to reload driver under
development after a change. It simply disables all devices and reenables
them when driver binary is updated. I encountered the same behaviour;
disabling devices using SetupDi APIs was very slow. Always, not only
under conditions you describe but it was at w2k and things could change
since then. Finally, I found another function which is much faster:
CM_Disable_DevNode(). You can try if something changes in your case; if
not, there is probably a different problem (non quite initialized device
stack as you presumed). Please note I can’t recommend to use this
function in production code as it is marked obsolete in docs and
probably doesn’t have expected side effects (coinstaller calls?) SetupDi
functions have.

(I wonder if at least one person on the world fully understands Setup
API :slight_smile:

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

> ----------
> From:
xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com]
on behalf of HP[SMTP:xxxxx@gmail.com]
> Reply To: Windows System Software Devs Interest List
> Sent: Monday, October 24, 2005 6:06 PM
> To: Windows System Software Devs Interest List
> Subject: [ntdev] Help disabling a device using SetupDiXXX fns after
WM_DEVICECHANGE msg
>
> 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,ARRAYSIZE(strReboot)))
> {
> return false;>
> }
> if
(!LoadString(NULL,IDS_ENABLE_FAILED,strFail,ARRAYSIZE(strFail)))
> {
> return false;
> }
>
> context.control = DICS_ENABLE; // DICS_PROPCHANGE DICS_ENABLE
DICS_DISABLE
> context.strSuccess = strEnable;
> }
> else
> {
> if
(!LoadString(NULL,IDS_DISABLED,strDisable,ARRAYSIZE(strDisable)))
> {
> return false;
> }
> if
(!LoadString(NULL,IDS_DISABLED_REBOOT,strReboot,ARRAYSIZE(strReboot)))
> {
> return false;
> }
> if
(!LoadString(NULL,IDS_DISABLE_FAILED,strFail,ARRAYSIZE(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 i
f 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,&devParams) &&
> (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.
>
> HP
>
> —
> Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
>
> You are currently subscribed to ntdev as: unknown lmsubst tag
argument: ‘’
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>

An idea: maybe this occurs if remove was vetoed by somebody?

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

----- Original Message -----
From: “HP”
To: “Windows System Software Devs Interest List”
Sent: Tuesday, October 25, 2005 8:29 PM
Subject: RE:[ntdev] Help disabling a device using SetupDiXXX fns after
WM_DEVICECHANGE msg

Thanks for the feedback - I’ve looked for information on
CM_Disable_DevNode, and it says everywhere that it must no longer be
used - ho hum!

The interesting thing I’ve seen when using the SetupDi APIs is that
it’s very fast as long as I’m not acting directly in response to a
WM_DEVICECHANGE message - that’s when it’s very slow for some reason.

Following on from my earlier message, I’ve found something that helps
with the 30 second delay problem. Instead of calling the
SetupDiSetClassInstallParams / SetupDiCallClassInstaller functionality
directly from the WM_DEVICECHANGE / DBT_DEVICEARRIVAL case, I now set
a variable containing the device id to indicate that disabling is
required. I’ve set up a timer to fire every 5 seconds, and in the
WM_TIMER case, I call the SetupDiSetClassInstallParams /
SetupDiCallClassInstaller functionality. The disabling takes place
immediately upon this code being called. I’m not sure why this
approach helps, but it does.

My changes have improved the responsiveness, but something else that I
see occasionally is that when I have sent a request to disable a
device, the device still looks enabled (no red cross through it) in
Device Manager and is accessible ? yet the right-click context menu
for the item in Device Manager shows an ?Enabled? option, giving the
impression that the device is disabled. This confusion seems to
remain until the computer is restarted.
Does anyone have an idea how to get around this, so that the state
changes in Device Manager and no restart is required?

Interestingly, I saw a similar phenomenon when I set the timer to a
shorter period, e.g. 1 second, - i.e. the device looked enabled in
Device Manager but it was still accessible and the context menu for it
showed an “Enable” option implying that it’s been disabled. It’s
almost as though the disabling had been “half-done” somehow.

I’d be very grateful if anyone has any ideas about the above behaviour
and possible ways of dealing with it, thanks again,

HP

> > ----------
> > From:
> xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com]
on behalf of Michal Vodicka[SMTP:xxxxx@upek.com]
> Reply To: Windows System Software Devs Interest List
> Sent: Monday, October 24, 2005 22:15:06
> To: Windows System Software Devs Interest List
> Subject: RE: [ntdev] Help disabling a device using SetupDiXXX fns after
WM_DEVICECHANGE msg
>
>
> Years before I wrote a small app which helps me to reload driver under
> development after a change. It simply disables all devices and reenables
> them when driver binary is updated. I encountered the same behaviour;
> disabling devices using SetupDi APIs was very slow. Always, not only
> under conditions you describe but it was at w2k and things could change
> since then. Finally, I found another function which is much faster:
> CM_Disable_DevNode(). You can try if something changes in your case; if
> not, there is probably a different problem (non quite initialized device
> stack as you presumed). Please note I can’t recommend to use this
> function in production code as it is marked obsolete in docs and
> probably doesn’t have expected side effects (coinstaller calls?) SetupDi
> functions have.
>
> (I wonder if at least one person on the world fully understands Setup
> API :slight_smile:
>
> Best regards,
>
> Michal Vodicka
> UPEK, Inc.
> [xxxxx@upek.com, http://www.upek.com]
>
>
> > ----------
> > From:
> xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com]
> on behalf of HP[SMTP:xxxxx@gmail.com]
> > Reply To: Windows System Software Devs Interest List
> > Sent: Monday, October 24, 2005 6:06 PM
> > To: Windows System Software Devs Interest List
> > Subject: [ntdev] Help disabling a device using SetupDiXXX fns after
> WM_DEVICECHANGE msg
> >
> > 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,ARRAYSIZE(strReboot)))
> > {
> > return false;>
> > }
> > if
> (!LoadString(NULL,IDS_ENABLE_FAILED,strFail,ARRAYSIZE(strFail)))
> > {
> > return false;
> > }
> >
> > context.control = DICS_ENABLE; // DICS_PROPCHANGE DICS_ENABLE
> DICS_DISABLE
> > context.strSuccess = strEnable;
> > }
> > else
> > {
> > if
> (!LoadString(NULL,IDS_DISABLED,strDisable,ARRAYSIZE(strDisable)))
> > {
> > return false;
> > }
> > if
> (!LoadString(NULL,IDS_DISABLED_REBOOT,strReboot,ARRAYSIZE(strReboot)))
> > {
> > return false;
> > }
> > if
> (!LoadString(NULL,IDS_DISABLE_FAILED,strFail,ARRAYSIZE(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 i
> f 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,&devParams) &&
> > (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.
> >
> > HP
> >
> > —
> > Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
> >
> > You are currently subscribed to ntdev as: unknown lmsubst tag
> argument: ‘’
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
> >


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com