View Single Post
Old 29-11-2007, 06:32 PM   #10
J Prendergast
Guest
 
Posts: n/a
RE: Help disabling a device using SetupDiXXX fns after WM_DEVICECH

Hi,

many thanks for sending this code. In the past day, I've found, with the
help of a colleague, that the reason for the 30 second delay seems to be that
I was calling the device control code in the same worker thread that is
receiving and processing Windows messages (e.g. WM_DEVICECHANGE) that are
sent by a synchronous SendMessage call. The code to process these messages
was not being executed at the point when the device control code is called,
and since the thread gets blocked until these messages are processed, the 30
second phenomena seems to have been due to a 30 second timeout on the sent
message expiring (i.e. it gives up on the message being handled and unblocks
the thread), and then the disable device code is executed finally.

Instead of directly requesting the device control functionality at the point
when a device is plugged in or enabled, I now post a Windows user message,
which ensures that the Windows message queue is still being processed, and on
receiving this Windows user message, I call the device control disabling
code, which gives an immediate result.

Thanks very much for sending the code and the explanation - I am going to
use the CMP_WaitNoPendingInstallEvents, at the time when I'm about to call
the device control (disabling) code, to ensure that it's a good time to do so
- thus eliminating possible "Your hardware has malfunctioned" or "Your
machine needs to be rebooted" messages.
Previously, if the SP_DEVINSTALL_PARAMS structure populated by my call to
SetupDiGetDeviceInstallParams to request disabling of the device indicated a
reboot is required (by setting the DI_NEEDRESTART and DI_NEEDREBOOT bits in
the Flags DWORD struct member) - my workaround was to have some retry code
whereby I would request enabling then disabling of the device, which cleared
the need for a reboot, usually the first time, but if not, I did another
retry (not ideal!).
Hopefully, using CMP_WaitNoPendingInstallEvents will eliminate the need for
this retry code.

Just as an aside - I don't use the DEVICE_NOTIFY_ALL_INTERFACE_CLASSES value
in my call to RegisterDeviceNotification, as this is only supported from
Windows XP onwards, and my application needs to also work on Windows 2000.

Many thanks for your help - it is very much appreciated.
I hope the solution to this problem helps others who experience similar
difficulties.

Best Regards,
JP


"Daniel Whitaker [MSFT]" wrote:

> Greetings,
>
> I sent you the code I promised. In short, and for the benefit of others,
> the best way to determine when the PNP Manager is finished with any install
> is to use the functions you have mentioned IN CONJUCTION with
> CMP_WaitNoPendingInstallEvents.
>
> This combo will give you the exact moment when the "You new hardware is now
> ready for use" bubble tip arrives.
>
> You may have noticed, depending upon how you called
> RegisterDeviceNotification, that the notification structure is NULL. This
> can keep you from determining the ID of the device that has arrived. The
> way around this is to call:
>
> hDevNotify = RegisterDeviceNotification(this->m_hWnd,
> &NotifcationFilter,
> DEVICE_NOTIFY_WINDOW_HANDLE |DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
>
> Now the notification structures will be filled with all sorts of
> information, including the ID of the arrived/departed device.
>
> Using WM_DEVICECHANGE by itself does provide a number of "arrivals",
> especially for USB devices. This is because your USB device, at a minimum,
> is also connected to a USB controller and a USB HUB. They all "arrive"
> when you plug something in, or even unplug it. So you need to sort of
> encapsulate the WM_DEVICECHANGE messages inside the use of
> CMP_WaitNoPendingInstallEvents.
>
> In this way you get something like the following:
>
> StartPNP
> Arrival <- Hub
> Arrival <- Controller
> Removal Query <- device
> Arrival <- device (final)
> CompletePNP
>
> Trying to access your device while inside this capsule can lead to, "Your
> hardware has malfunctioned" or "Your machine needs to be rebooted".
>
> So what I do is create an OnTimer function that gets fired every second and
> checks the return value of CMP_WaitNoPendingInstallEvents. Like this:
>
> OnTimer(UINT nIDEvent)
> {
> DWORD dwRet;
> switch(nIDEvent)
> {
> case PNP_TIMER: // defined elsewhere
> KillTimer(PNP_TIMER);
> dwRet = CMP_WaitNoPendingInstallEvents(0); // returns
> immediately
> switch(dwRet)
> {
> case WAIT_OBJECT_0: // PNP complete
> if(m_bPNPActive) // global flag defined elsewhere
> {
> m_bPNPActive = FALSE;
> // do something, set an event, send a
> message, etc
> }
> break;
> case WAIT_TIMEOUT:
> if(!m_bPNPActive) // do something like
> m_ctlList.InsertString(0,"PNP Installing, please wait");
> m_bPNPActive = TRUE;
> break;
> case WAIT_FAILED: // something bad happened
> break;
> }
> SetTimer(PNP_TIMER,1000,NULL);
> return;
> }
> CDialog::OnTimer(nIDEvent)
> }
>
> There are other ways to monitor PNP, but this is just one of them.
> Basically, when WAIT_OBJECT_0 is returned, the "Your hardware is ready to
> use" comes up within a second after that. By the way, this works for
> ServerSide installs as well as ClientSide installs.
>
> Hope this helps!
>
> Daniel Whitaker
> Microsoft DDK Team
>
> This posting is provided "AS IS" with no warranties, and confers no rights

  Reply With Quote