Re: Help disabling a device using SetupDiXXX fns after WM_DEVICECH
- From: "Pavel A." <pavel_a@xxxxxxxxxxxxxxx>
- Date: Sat, 26 Nov 2005 23:18:16 +0200
"J Prendergast" <j.prendergast@xxxxxxxxxxxxx> wrote in message news:8E503237-6F8F-4CDA-85DB-BF9157EE4BC7@xxxxxxxxxxxxxxxx
> Hi, the intention of my application is to disable certain types of device -
> to prevent users from accessing them. If any such "banned" device is plugged
> in, or is already present and a request is made to enable it in Device
> Manager, the application must respond as soon as possible by disabling the
> device. The need to disable as opposed to uninstalling the device is so that
> banned devices are disabled immediately and will then be shown with a red
> cross through them in Device Manager.
Sorry but it looks kind of paranoid :(
It is easily possible to prevent non-admin users from installing new devices,
or from enabling devices from dev.manager.
OTOH, an admin user can track your application and kill it,
or re-enable the device again.
Regards,
--PA
> I can't find an enable example in the DDK - as I mentioned, my code for
> enabling / disabling is based on the code in the DDK devcon example. Like
> devcon, my code works absolutely fine for disabling devices when it's an
> independent request (e.g. click on a button and disable a device).
>
> My problem lies with sending disable requests in response to a received
> WM_MESSAGE / DBT_DEVICEARRIVAL message - and knowing when the
> newly-plugged-in device is fully initialised (the PNP 'install thread' has
> completed) so that I can send a disable request and get an immediate result
> (instead of getting a 30 second delay before the device is disabled).
>
> No DDK example implements this functionality specifically, so I don't have
> one to compare against.
>
> If anyone has any suggestions / advice that will help with this (full
> details in my original message), I'd be very grateful.
>
> Regards,
> JP
>
> "Arkady Frenkel" wrote:
>
>> Additionally , check that behaviour with enable example from DDK
>> Arkady
>>
>> "Pavel A." <pavel_a@xxxxxxxxxxxxxxx> wrote in message
>> news:uS6BXDV8FHA.3380@xxxxxxxxxxxxxxxxxxxxxxx
>> > Hi,
>> > If you don't like some devices, why you just won't disable or uninstall
>> > them?
>> >
>> > --PA
>> >
>> > "J Prendergast" <j.prendergast@xxxxxxxxxxxxx> wrote in message
>> > news:A5F82183-E04A-4559-9F6B-C482FC8CE363@xxxxxxxxxxxxxxxx
>> >> 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).
>> >>
>> >> The issue I have 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?
>> >>
>> >> My progress so far:
>> >> 1) 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.
>> >>
>> >> 2) Something that does actually help with the 30 second delay problem in
>> >> the
>> >> case where a device is enabled in Device Manager - instead of calling the
>> >> SetupDiSetClassInstallParams / SetupDiCallClassInstaller functionality
>> >> directly from the WM_DEVICECHANGE / DBT_DEVICEARRIVAL case, I now set a
>> >> variable containing the device id and fire an event to indicate that
>> >> disabling is required. In the code that waits for the event, 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.
>> >>
>> >> 3) While the above approach helps in the situation where a device is
>> >> enabled, it doesn't help in the case when a device is plugged in. In this
>> >> case, the WM_DEVICECHANGE / DBT_DEVICEARRIVAL message is received, the
>> >> event
>> >> is fired, but the code to disable the device takes around 30 seconds to
>> >> take
>> >> effect. I have heard that this is because...
>> >> "there is a difference when you are adding a new device/enabling for the
>> >> first time. Windows creates a special thread for the install and will not
>> >> allow other "PNP" events to occur until it completes. They sort of line
>> >> up in
>> >> a row and then are sent through this thread pipe. There is a timeout
>> >> value of
>> >> up to 2 minutes, but generally it seems to be about 30 seconds to a
>> >> minute.
>> >> Calling the ClassInstaller when the thread is active would probably cause
>> >> a
>> >> delay because of the install thread."
>> >>
>> >> Something that *does work* but is unacceptable for my application is to
>> >> set
>> >> a timer that periodically checks whether a device needs to be disabled,
>> >> and
>> >> provided the time between the WM_DEVICECHANGE / DBT_DEVICEARRIVAL message
>> >> being received and the timer firing to request disabling of the device
>> >> exceeds 3 seconds or so, the disabling takes place immediately. If the
>> >> timer
>> >> is for a shorter period, then it would take 30 seconds or more.
>> >>
>> >> Ideally, I would prefer not to use a timer to wait for a specific amount
>> >> of
>> >> time for the newly-added device to be fully installed - as I appreciate
>> >> that
>> >> this may vary from computer to computer, and maybe even from device to
>> >> device.
>> >>
>> >> Does anyone know a way whereby I can detect / get a notification when a
>> >> device is fully initialised (i.e. when the special thread for the install
>> >> has
>> >> completed) after being plugged in?
>> >> (at which time, I would be guaranteed a "safe" time to request disabling
>> >> and
>> >> get an immediate response.)
>> >> The WM_DEVICECHANGE message with DBT_DEVICEARRIVAL wParam seems to tell
>> >> me
>> >> the instant it is plugged in, but before it is all initialised and safe
>> >> to
>> >> send to a disable request.
>> >>
>> >> Thanks in advance for any ideas / comments about the above behaviour and
>> >> possible ways of dealing with it.
>> >>
>> >> JP
>> >>
>> >> PS 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;
.
- References:
- Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE
- From: J Prendergast
- Re: Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE
- From: Pavel A.
- Re: Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE
- From: Arkady Frenkel
- Re: Help disabling a device using SetupDiXXX fns after WM_DEVICECH
- From: J Prendergast
- Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE
- Prev by Date: Re: documentation of per-process and per-thread kernel structures?
- Next by Date: Re: Converting an exe to a dll.
- Previous by thread: Re: Help disabling a device using SetupDiXXX fns after WM_DEVICECH
- Next by thread: RE: Help disabling a device using SetupDiXXX fns after WM_DEVICECHANGE
- Index(es):
Loading