/**************************************************************************\
* Module Name: instdev.c
*
* Device handling routine for CSRSS.
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Created: 13-Mar-97
*
* History:
*   13-Mar-97 created by PaulaT
\**************************************************************************/

#include "precomp.h"
#pragma hdrstop

#include "ntuser.h"
#include <dbt.h>
#include <pnpmgr.h>


/**************************************************************************\
* SrvDeviceEvent
*
* User-mode PNP manager (in services.exe) has a message to deliver to an
* app that has registered for this notification but services.exe isn't
* in WinSta0\Default so we need a CSRSS thread to simply send the message.
*
* PaulaT    06/04/97    Created.
* JasonSch  02/22/01    Removed bogus try/except.
\**************************************************************************/
ULONG
SrvDeviceEvent(
    IN OUT PCSR_API_MSG m,
    IN OUT PCSR_REPLY_STATUS ReplyStatus)
{
    NTSTATUS Status;
    PDEVICEEVENTMSG a = (PDEVICEEVENTMSG)&m->u.ApiMessageData;
    USERTHREAD_USEDESKTOPINFO utudi;

    UNREFERENCED_PARAMETER(ReplyStatus);

    //
    // Set the desktop to the active desktop before sending the
    // message.
    //

    utudi.hThread = NULL;
    utudi.drdRestore.pdeskRestore = NULL;
    Status = NtUserSetInformationThread(NtCurrentThread(),
                                        UserThreadUseActiveDesktop,
                                        &utudi, sizeof(utudi));
    if (!NT_SUCCESS(Status)) {
        RIPMSG1(RIP_WARNING, "SrvDeviceEvent: NtUserSetInformationThread failed 0x%x\n", Status);
        goto Exit;
    }

    //
    // Verify the window handle is still valid. If not, let the caller know
    // so it can be purged from the notification window list that the
    // user-mode pnp manager keeps.
    //

    if (a->hWnd != HWND_BROADCAST && !IsWindow(a->hWnd)) {
        Status = STATUS_INVALID_HANDLE;
        goto ResetDesktop;
    }

    if (a->dwFlags) {

        //
        // This is a query so we have to send the message but use
        // timeouts so an app can't stall us forever.
        //

        RIPMSG3(RIP_VERBOSE, "SrvDeviceEvent: Sending WM_DEVICECHANGE to 0x%x, w 0x%p, l 0x%p",
                a->hWnd,
                a->wParam,
                a->lParam);


        if (!SendMessageTimeout(a->hWnd, WM_DEVICECHANGE, a->wParam, a->lParam,
                                SMTO_ABORTIFHUNG | SMTO_NORMAL,
                                PNP_NOTIFY_TIMEOUT, &a->dwResult)) {
            Status = STATUS_UNSUCCESSFUL;
        }
    } else {
        //
        // It's not a query so just post it and return. We don't
        // care what the app returns.
        //

        RIPMSG3(RIP_VERBOSE, "SrvDeviceEvent: Posting WM_DEVICECHANGE to 0x%x, w 0x%p, l 0x%p",
                a->hWnd,
                a->wParam,
                a->lParam);

        if (!PostMessage(a->hWnd, WM_DEVICECHANGE, a->wParam, a->lParam)) {
            Status = STATUS_UNSUCCESSFUL;
        }
    }

ResetDesktop:

    //
    // Reset this thread's desktop back to NULL before returning. This
    // decrements the desktop's reference count.
    //

    NtUserSetInformationThread(NtCurrentThread(),
                               UserThreadUseDesktop,
                               &utudi, sizeof(utudi));

Exit:
    return Status;
}