示例#1
0
NTSTATUS UserClientConnect(
    PCSR_PROCESS Process,
    PVOID ConnectionInformation,
    PULONG pulConnectionLen)
{
    PHANDLE pHandle = Process->ServerDllPerProcessData[USERSRV_SERVERDLL_INDEX];
    int i;

    /*
     * Pass the api port to the kernel.  Do this early so the kernel
     * can send a datagram to CSR to activate a debugger.
     */
    if (CsrApiPort == NULL) {
        CsrApiPort = CsrQueryApiPort();
        NtUserSetInformationThread(
                NtCurrentThread(),
                UserThreadCsrApiPort,
                &CsrApiPort,
                sizeof(HANDLE));
    }

    /*
     * Initialize cached handles to NULL
     */
    for (i = 0; i < CHANDLES; ++i)
        pHandle[i] = NULL;

    return NtUserProcessConnect(Process->ProcessHandle,
            (PUSERCONNECT)ConnectionInformation, *pulConnectionLen);
}
示例#2
0
ULONG
SrvDeviceEvent(
    IN OUT PCSR_API_MSG m,
    IN OUT PCSR_REPLY_STATUS ReplyStatus)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PDEVICEEVENTMSG a = (PDEVICEEVENTMSG)&m->u.ApiMessageData;
    USERTHREAD_USEDESKTOPINFO utudi;

    UNREFERENCED_PARAMETER(ReplyStatus);

    try {

        //
        // 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)) {
            #if DBG
            KdPrint(("--> SrvDeviceEvent: NtUserSetInformationThread failed %d\n", Status));
            #endif
            goto Clean1;
        }

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

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

        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%x, l 0x%x",
                    (ULONG_PTR)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%x, l 0x%x",
                    (ULONG_PTR)a->hWnd,
                    a->wParam,
                    a->lParam);

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

    Clean0:

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

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

    Clean1:
        ;

    } except (EXCEPTION_EXECUTE_HANDLER) {
        KdPrint(("SrvDeviceEvent generated an exception (%d)\n", GetExceptionCode()));
        Status = STATUS_UNSUCCESSFUL;
    }

    return Status;

} // SrvDeviceEvent
示例#3
0
VOID HandleMediaChangeEvent( UINT uidCdRom )
{
    /*
     * Local variables
     */
    HANDLE                  hDevice;
    ULONG                   id;
    DWORD                   cb;
    DWORD                   dwLogicalDrives;
    DWORD                   dwDriveMask;
    DWORD                   dwDriveCount;
    DWORD                   dwRecipients;
    BOOL                    bResult;
    INT                     nCurrentTry;
    NTSTATUS                Status;
    UNICODE_STRING          ustrCdRom;
    UNICODE_STRING          ustrCdRomId;
    UNICODE_STRING          ustrAnyCdRom;
    UNICODE_STRING          ustrNtPath;
    DEV_BROADCAST_VOLUME    dbcvInfo;
    LPWSTR                  lpszCdRom = TEXT("\\Device\\CdRom");
    WCHAR                   szDrive[] = TEXT("A:\\");
    WCHAR                   szDevice[] = TEXT("\\\\.\\A:");
    WCHAR                   wcDrive;
    WCHAR                   szCdRom[32];
    WCHAR                   szBuff[256];


    UserAssert(uidCdRom >= 0 && uidCdRom < NUM_MEDIA_EVENTS);  // at most 24 cd-rom drives in system


    /*
     * Some initializations
     */
    RtlInitUnicodeString( &ustrAnyCdRom, lpszCdRom );
    wcDrive = UNICODE_NULL;

    /*
     * Form the \Device\CdRomX name based on uidCdRom
     */
    wsprintfW( szCdRom, L"\\Device\\CdRom%d", uidCdRom );
    RtlInitUnicodeString( &ustrCdRom, szCdRom );

    /*
     * The uidCdRom parameter tells us which CD-ROM device generated the
     * MediaChange event.  We need to map this device back to it's logical
     * drive letter because WM_DEVICECHANGE is based on drive letters.
     *
     * To avoid always searching all logical drives, we cache the last
     * associated drive letter.  We still need to check this every time
     * we get notified because WinDisk can remap drive letters.
     */
    if (wcDriveCache[uidCdRom]) {
        /*
         * Convert our DOS path name to a NT path name
         */
        ustrNtPath.MaximumLength = sizeof(szBuff);
        ustrNtPath.Length = 0;
        ustrNtPath.Buffer = szBuff;
        bResult = GetDeviceObject(wcDriveCache[uidCdRom], &ustrNtPath);
        if (bResult) {
            /*
             * Check to see if this drive letter is the one that maps
             * to the CD-ROM drive that just notified us.
             */
            if (RtlEqualUnicodeString(&ustrCdRom, &ustrNtPath, TRUE)) {
                /*
                 * Yes, we found a match
                 */
                wcDrive  = wcDriveCache[uidCdRom];
            }
        }
    }

    if (!wcDrive) {
        /*
         * Either the cache wasn't initialized, or we had a re-mapping
         * of drive letters.  Scan all drive letters looking for CD-ROM
         * devices and update the cache as we go.
         */
        RtlZeroMemory(wcDriveCache, sizeof(wcDriveCache));
        szDrive[0] = L'A';
        szDevice[4] = L'A';
        dwDriveCount = 26; //Max number of drive letters
        dwDriveMask = 1; //Max number of drive letters
        dwLogicalDrives = GetLogicalDrives();

        while (dwDriveCount) {
            /*
             * Is this logical drive a CD-ROM?
             */

//
// JOHNC - Remove after GetDriveType() is fixed
            if ((dwLogicalDrives & dwDriveMask) &&
                GetDriveType(szDrive) == DRIVE_CDROM) {
                /*
                 * For this CD-ROM drive, find it's NT path.
                 */
                ustrNtPath.MaximumLength = sizeof(szBuff);
                ustrNtPath.Length = 0;
                ustrNtPath.Buffer = szBuff;
                bResult = GetDeviceObject(szDrive[0], &ustrNtPath);
                if (bResult) {
                    /*
                     * Make sure the string is in the form \Device\CdRom
                     */
                    if (RtlPrefixUnicodeString(&ustrAnyCdRom, &ustrNtPath, TRUE)) {
                        /*
                         * Now find it's id.  We have a string that looks like
                         * \Device\CdRom??? where ??? is the unit id
                         */
                        RtlInitUnicodeString(&ustrCdRomId,
                                             (PWSTR)((PSTR)(ustrNtPath.Buffer)+ustrAnyCdRom.Length));
                        RtlUnicodeStringToInteger(&ustrCdRomId, 10, &id);
                        UserAssert(id >= 0 && id < NUM_MEDIA_EVENTS);
                        wcDriveCache[id] = szDrive[0];

                            //Initially set State to Unknown
                        aDriveState[id] = DS_UNKNOWN;

                        /*
                         * If this is the device that notified us, remember its
                         * drive letter so we can broadcase WM_DEVICECHANGE
                         */
                        if (uidCdRom == id) {
                            wcDrive  = szDrive[0];
                        }
                    }
                }
            }

            /*
             * Try the next drive
             */
            szDrive[0] = szDrive[0] + 1;
            szDevice[4] = szDevice[4] + 1;
            dwDriveMask <<= 1;
            --dwDriveCount;
        }
    }

    /*
     * If we found a logical drive, determine the media state for the drive
     * and broadcast the WM_DEVICECHANGE notification.
     */
    if (wcDrive) {
        /*
         * Get the Media status of this drive.  Assume media is not
         * present in the case of an error.
         */
        szDevice[4] = wcDrive;

        hDevice = CreateFile(szDevice,
                             GENERIC_READ,
                             FILE_SHARE_READ,
                             NULL,
                             OPEN_EXISTING,
                             FILE_ATTRIBUTE_NORMAL,
                             NULL);
        if (hDevice == INVALID_HANDLE_VALUE) {
#ifdef DEBUG
        KdPrint(("        CreateFile( '%ls' ) Failed. Error %lx\n",
                szDevice,GetLastError()));
#endif
            return;
        }

        /*
         * Loop and check the CD-ROM to see if media is available.  We need
         * this loop because some CD-ROM drives notify us that media has
         * arrived before the drive has recognized that it had new media.
         */
        for (nCurrentTry = 0; nCurrentTry < MAX_TRIES; nCurrentTry++) {

            /*
             * See if media is present
             */
            bResult = (DWORD)DeviceIoControl(hDevice,
                                             IOCTL_DISK_CHECK_VERIFY,
                                             NULL,
                                             0,
                                             NULL,
                                             0,
                                             &cb,
                                             NULL);

            if (bResult) {
                /*
                 * Media is present, change the state to Inserted.
                 */
                aDriveState[uidCdRom] = DS_INSERTED;
                break;
            }

            /*
             * Media wasn't present, so we need to look at GetLastError() to see
             * if DeviceIoControl() failed.  If so we may want to try again.
             */
            if (GetLastError() == ERROR_NOT_READY) {
                Sleep(500); // 1/2 second

                /*
                * We only want to retry if we the prev State was UNKNOWN or
                * EJECTED. If the previous State was INSERTED it means that
                * this event is the removal event
                */
                if(aDriveState[uidCdRom]== DS_UNKNOWN ||
                        aDriveState[uidCdRom] == DS_EJECTED) {
                    continue;

                }
            }

            /*
             * Call failed.  Assume worst case and say the media has been removed.
             */
            aDriveState[uidCdRom] = DS_EJECTED;
            break;
        }

        /*
         * Close the handle to the CD-ROM device
         */
        CloseHandle(hDevice);

        /*
         * Initialize the structures used for BroadcastSystemMessage
         */
        dbcvInfo.dbcv_size = sizeof(dbcvInfo);
        dbcvInfo.dbcv_devicetype = DBT_DEVTYP_VOLUME;
        dbcvInfo.dbcv_reserved = 0;
        dbcvInfo.dbcv_flags = DBTF_MEDIA;
        dbcvInfo.dbcv_unitmask = (1 << (wcDrive - L'A'));

        dwRecipients = BSM_ALLCOMPONENTS | BSM_ALLDESKTOPS;

        /*
         * Temporarily we must assign this thread to a desktop so we can
         * call USER's BroascastSystemMessage() routine.  We call the
         * private SetThreadDesktopToDefault() to assign ourselves to the
         * desktop that is currently receiving input.
         */
        Status = NtUserSetInformationThread(NtCurrentThread(),
                                            UserThreadUseActiveDesktop,
                                            NULL, 0);
        if (NT_SUCCESS(Status)) {
            /*
             * Broadcast the message
             */
            BroadcastSystemMessage(BSF_FORCEIFHUNG,
                                   &dwRecipients,
                                   WM_DEVICECHANGE,
// HACK: need to or 0x8000 in wParam
//       because this is a flag to let
//       BSM know that lParam is a pointer
//       to a data structure.
                                   0x8000 | ((bResult) ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE),
                                   (LPARAM)&dbcvInfo);

#ifdef DEBUG
        KdPrint(("        Message Broadcast for '%lc:'\n", wcDrive));
#endif
            /*
             * Set our thread's desktop back to NULL.  This will decrement
             * the desktop's reference count.
             */
            hDevice = NULL;
            NtUserSetInformationThread(NtCurrentThread(),
                                       UserThreadUseDesktop,
                                       &hDevice, // hDevice = NULL
                                       sizeof(HANDLE));
        }
    }
}
示例#4
0
LONG APIENTRY EndTaskDlgProc(
    HWND hwndDlg,
    UINT msg,
    UINT wParam,
    LONG lParam)
{
    ENDDLGPARAMS* pedp;
    LARGE_INTEGER li;
    WCHAR achFormat[CCHBODYMAX];
    WCHAR achText[CCHBODYMAX];
    DWORD dwData;
    USERTHREAD_FLAGS Flags;

    switch (msg) {
    case WM_INITDIALOG:
        pedp = (ENDDLGPARAMS*)lParam;

        /*
         * Save this for later revalidation.
         */
        SetWindowLong(hwndDlg, GWL_USERDATA, (DWORD)pedp->h);
        SetWindowLong(hwndDlg, DWL_USER, (DWORD)pedp->type);

        SetWindowText(hwndDlg, pedp->pszTitle);

        /*
         * Update text that says how long we'll wait.
         */
        GetDlgItemText(hwndDlg, IDIGNORE, achFormat, CCHBODYMAX);
        wsprintf(achText, achFormat, pedp->cSeconds);
        SetDlgItemText(hwndDlg, IDIGNORE, achText);

        /*
         * Make this dialog top most and foreground.
         */
        Flags.dwFlags = TIF_ALLOWFOREGROUNDACTIVATE;
        Flags.dwMask = TIF_ALLOWFOREGROUNDACTIVATE;
        NtUserSetInformationThread(NtCurrentThread(), UserThreadFlags,
                &Flags, sizeof(Flags));
        SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0,
                SWP_NOMOVE | SWP_NOSIZE);

        /*
         * Set this timer so every 1/2 a second we can see if this app
         * has gone away.
         */
        SetTimer(hwndDlg, 5, 500, NULL);
        return TRUE;

    case WM_TIMER:
        /*
         * If shutdown has been cancelled, bring down the dialog.
         */
        li.QuadPart  = 0;
        if (NtWaitForSingleObject(heventCancel, FALSE, &li) == 0) {
            EndDialog(hwndDlg, IDCANCEL);
            break;
        }

        dwData = GetWindowLong(hwndDlg, GWL_USERDATA);
        if (GetWindowLong(hwndDlg, DWL_USER) == TYPE_CONSOLE_ID) {

            /*
             * If it's the console calling us, check if the thread or process
             * handle is still valid. If not, bring down the dialog.
             */
            if (WaitForSingleObject((HANDLE)dwData, 0) != 0)
                break;
        } else if (!(((PCSR_THREAD)dwData)->Flags & CSR_THREAD_DESTROYED)) {

            /*
             * If the thread is marked as destroyed, bring down the dialog.
             */
            break;
        }

        /*
         * This'll cause the dialog to go away and the wait for this app to
         * close to return.
         */
        EndDialog(hwndDlg, IDRETRY);
        break;

    case WM_CLOSE:
        /*
         * Assume WM_CLOSE means cancel shutdown
         */
        wParam = IDCANCEL;
        /*
         * falls through...
         */

    case WM_COMMAND:
        EndDialog(hwndDlg, LOWORD(wParam));
        break;
    }

    return FALSE;
}
示例#5
0
NTSTATUS _ExitWindowsEx(
    PCSR_THREAD pcsrt,
    UINT dwFlags,
    DWORD dwReserved)
{
    BOOL fDoEndSession = FALSE;
    LUID luidCaller;
    NTSTATUS Status = STATUS_SUCCESS;
    UNREFERENCED_PARAMETER(dwReserved);

    if ((dwFlags & EWX_REBOOT) || (dwFlags & EWX_POWEROFF)) {
        dwFlags |= EWX_SHUTDOWN;
    }

    /*
     * Find out the callers sid. Only want to shutdown processes in the
     * callers sid.
     */
    if (!CsrImpersonateClient(NULL)) {
        return STATUS_BAD_IMPERSONATION_LEVEL;
    }

    Status = CsrGetProcessLuid(NULL, &luidCaller);

    if (!NT_SUCCESS(Status)) {
        CsrRevertToSelf();
        return Status;
    }

    try {

        while (1) {
            LARGE_INTEGER li;

            LeaveCrit();
            Status = NtUserSetInformationThread(
                    pcsrt->ThreadHandle,
                    UserThreadInitiateShutdown,
                    &dwFlags, sizeof(dwFlags));
            EnterCrit();
            switch (Status) {
            case STATUS_PENDING:

                /*
                 * The logoff/shutdown is in progress and nothing
                 * more needs to be done.
                 */
                goto fastexit;

            case STATUS_RETRY:

                /*
                 * Another logoff/shutdown is in progress and we need
                 * to cancel it so we can do an override.
                 *
                 * if someone else is trying to cancel shutdown, exit
                 */
                li.QuadPart  = 0;
                if (NtWaitForSingleObject(heventCancel, FALSE, &li) == 0) {
                    Status = STATUS_PENDING;
                    goto fastexit;
                }

                /*
                 * Cancel the old shutdown
                 */
                NtClearEvent(heventCancelled);
                NtSetEvent(heventCancel, NULL);

                /*
                 * Wait for the other guy to be cancelled
                 */
                LeaveCrit();
                NtWaitForSingleObject(heventCancelled, FALSE, NULL);
                EnterCrit();

                /*
                 * This signals that we are no longer trying to cancel a
                 * shutdown
                 */
                NtClearEvent(heventCancel);
                continue;

            case STATUS_CANT_WAIT:

                /*
                 * There is no notify window and the calling thread has
                 * windows that prevent this request from succeeding.
                 * The client handles this by starting another thread
                 * to recall ExitWindowsEx.
                 */
                goto fastexit;

            default:
                if (!NT_SUCCESS(Status))
                    goto fastexit;
            }
            break;
        }

        gdwFlags = dwFlags;
        dwThreadEndSession = (DWORD)pcsrt->ClientId.UniqueThread;
        fDoEndSession = TRUE;

        /*
         * Sometimes the console calls the dialog box when not in shutdown
         * if now is one of those times cancel the dialog box.
         */
        while (gcInternalDoEndTaskDialog > 0) {
            LARGE_INTEGER li;

            NtPulseEvent(heventCancel, NULL);

            LeaveCrit();
            li.QuadPart = (LONGLONG)-10000 * CMSSLEEP;
            NtDelayExecution(FALSE, &li);
            EnterCrit();
        }

        /*
         * Call csr to loop through the processes shutting them down.
         */
        LeaveCrit();
        Status = CsrShutdownProcesses(&luidCaller, dwFlags);

        NtUserSetInformationThread(
                pcsrt->ThreadHandle,
                UserThreadEndShutdown, &Status, sizeof(Status));
        EnterCrit();
fastexit:;
    } finally {
        /*
         * Only turn off dwThreadEndSession if this is the
         * thread doing shutdown.
         */
        if (fDoEndSession) {
            dwThreadEndSession = 0;
            NtSetEvent(heventCancelled, NULL);
        }
    }

    CsrRevertToSelf();

    return Status;
}
示例#6
0
DWORD MySendEndSessionMessages(
    HWND hwnd,
    PCSR_THREAD pcsrt,
    BOOL fEndTask,
    DWORD dwClientFlags)
{
    HWND hwndOwner;
    LARGE_INTEGER li;
    DWORD dwRet;
    int cLoops;
    int cSeconds;
    WCHAR achName[CCHBODYMAX];
    BOOL fPostedClose;
    BOOL fDialogFirst;
    DWORD dwFlags;
    DWORD dwHungApp;
    HANDLE hNull = NULL;
    NTSTATUS Status;

    /*
     * We've got a random top level window for this application. Find the
     * root owner, because that's who we want to send the WM_CLOSE to.
     */
    while ((hwndOwner = GetWindow(hwnd, GW_OWNER)) != NULL)
        hwnd = hwndOwner;

    /*
     * We expect this application to process this shutdown request,
     * so make it the foreground window so it has foreground priority.
     * This won't leave the critical section.
     */
    SetForegroundWindow(hwnd);

    /*
     * Send the WM_CLIENTSHUTDOWN message for end-session. When the app
     * receives this, it'll then get WM_QUERYENDSESSION and WM_ENDSESSION
     * messages.
     */
    if (!fEndTask) {
        USERTHREAD_FLAGS Flags;

        Flags.dwFlags = 0;
        Flags.dwMask = (TIF_SHUTDOWNCOMPLETE | TIF_ALLOWSHUTDOWN);
        LeaveCrit();
        Status = NtUserSetInformationThread(pcsrt->ThreadHandle,
                UserThreadFlags, &Flags, sizeof(Flags));
        EnterCrit();
        if (!NT_SUCCESS(Status))
            return CMDEND_APPSAYSOK;

        SendNotifyMessage(hwnd, WM_CLIENTSHUTDOWN, dwClientFlags, 0);
    }

    /*
     * If the main window is disabled, bring up the end-task window first,
     * right away, only if this the WM_CLOSE case.
     */
    fDialogFirst = FALSE;
    if (fEndTask && (GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED))
        fDialogFirst = TRUE;

    fPostedClose = FALSE;
    while (TRUE) {
        if (fEndTask) {
            cLoops   = (CMSHUNGAPPTIMEOUT / CMSSLEEP);
            cSeconds = (CMSHUNGAPPTIMEOUT / 1000);
        }
        else {
            cLoops   = (CMSWAITTOKILLTIMEOUT / CMSSLEEP);
            cSeconds = (CMSWAITTOKILLTIMEOUT / 1000);
        }

        /*
         * If end-task and not shutdown, must give this app a WM_CLOSE
         * message. Can't do this if it has a dialog up because it is in
         * the wrong processing loop. We detect this by seeing if the window
         * is disabled - if it is, we don't send it a WM_CLOSE and instead
         * bring up the end task dialog right away (this is exactly compatible
         * with win3.1 taskmgr.exe).
         */
        if (fEndTask) {
            if (!fPostedClose && IsWindow(hwnd) &&
                    !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED)) {
                PostMessage(hwnd, WM_CLOSE, 0, 0L);
                fPostedClose = TRUE;
            }
        }

        /*
         * Every so often wake up to see if the app is hung, and if not go
         * back to sleep until we've run through our timeout.
         */
        while (cLoops--) {
            /*
             * If a WM_QUERY/ENDSESSION has been answered to, return.
             */
            if (!fEndTask) {
                LeaveCrit();
                NtUserQueryInformationThread(pcsrt->ThreadHandle,
                        UserThreadFlags, &dwFlags, sizeof(DWORD), NULL);
                EnterCrit();
                if (dwFlags & TIF_SHUTDOWNCOMPLETE) {
                    if (dwFlags & TIF_ALLOWSHUTDOWN)
                        return CMDEND_APPSAYSOK;
                    return CMDEND_APPSAYSNOTOK;
                }
            }

            /*
             * If the thread is gone, we're done.
             */
            if (pcsrt->Flags & CSR_THREAD_DESTROYED) {
                return CMDEND_APPSAYSOK;
            }

            /*
             * If the dialog should be brought up first (because the window
             * was initially disabled), do it.
             */
            if (fDialogFirst) {
                fDialogFirst = FALSE;
                break;
            }

            /*
             * if we we're externally cancelled get out
             */
            li.QuadPart = 0;
            if (NtWaitForSingleObject(heventCancel, FALSE, &li) == 0) {

                /*
                 * !!! JimA - We may want to call the kernel to
                 * set TIF_SHUTDOWNCOMPLETE in this case.
                 */
                return CMDEND_USERSAYSCANCEL;
            }

            /*
             * If hung, bring up the endtask dialog right away.
             */
            dwHungApp = (fEndTask ? CMSHUNGAPPTIMEOUT : CMSWAITTOKILLTIMEOUT);
            LeaveCrit();
            Status = NtUserQueryInformationThread(pcsrt->ThreadHandle,
                    UserThreadHungStatus, &dwHungApp, sizeof(dwHungApp), NULL);
            EnterCrit();
            if (!NT_SUCCESS(Status) || dwHungApp == TRUE)
                break;

            /*
             * Sleep for a second.
             */
            LeaveCrit();
            li.QuadPart = (LONGLONG)-10000 * CMSSLEEP;
            NtDelayExecution(FALSE, &li);
            EnterCrit();
        }

        achName[0] = 0;
        if (IsWindow(hwnd)) {
            GetWindowText(hwnd, achName, CCHMSGMAX);
        }

        /*
         * If there's a hard error, put it on top.
         */
        BoostHardError((DWORD)pcsrt->ClientId.UniqueProcess, FALSE);

        if (achName[0] == 0) {

            /*
             * If the thread is gone, we're done.
             */
            if (pcsrt->Flags & CSR_THREAD_DESTROYED) {
                return CMDEND_APPSAYSOK;
            }

            /*
             * pti is valid right now. Use the name in the pti.
             */
            LeaveCrit();
            NtUserQueryInformationThread(pcsrt->ThreadHandle,
                    UserThreadTaskName, achName, CCHMSGMAX * sizeof(WCHAR),
                    NULL);
            EnterCrit();
        }

        /*
         * Set this thread to use the desktop of the
         * thread being shutdown.
         */
        if (NT_SUCCESS(NtUserSetInformationThread(NtCurrentThread(),
                UserThreadUseDesktop, &pcsrt->ThreadHandle, sizeof(HANDLE)))) {

            /*
             * Bring up the dialog
             */
            dwRet = DoEndTaskDialog(achName, pcsrt,
                                        TYPE_THREADINFO, cSeconds);

            /*
             * Release the desktop that was used.
             */
            NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop,
                    &hNull, sizeof(HANDLE));
        } else {

            /*
             * We were unable to get the thread's desktop.  All we
             * can do is kill the task.
             */
            dwRet = IDABORT;
        }

        switch(dwRet) {
        case IDCANCEL:
            /*
             * Cancel the shutdown process... Get out of here. Signify that
             * we're cancelling the shutdown request.
             *
             * !!! JimA - We may want to call the kernel to
             * set TIF_SHUTDOWNCOMPLETE in this case.
             */
            return CMDEND_USERSAYSCANCEL;
            break;

        case IDABORT:
            /*
             * End this guy's task...
             */
            BoostHardError((DWORD)pcsrt->ClientId.UniqueProcess, TRUE);

            /*
             * !!! JimA - We may want to call the kernel to
             * set TIF_SHUTDOWNCOMPLETE in this case.
             */
            return CMDEND_USERSAYSKILL;
            break;

        case IDRETRY:
            /*
             * Just continue to wait. Reset this app so it doesn't think it's
             * hung. This'll cause us to wait again.
             */
            if (!(pcsrt->Flags & CSR_THREAD_DESTROYED)) {
                LeaveCrit();
                NtUserSetInformationThread(pcsrt->ThreadHandle,
                        UserThreadHungStatus, NULL, 0);
                EnterCrit();
            }
            fPostedClose = FALSE;
            break;
        }
    }
}
示例#7
0
BOOL _EndTask(
    HWND hwnd,
    BOOL fShutdown,
    BOOL fMeanKill)
{
    PCSR_THREAD pcsrt = CSR_SERVER_QUERYCLIENTTHREAD();
    PCSR_THREAD pcsrtKill;
    DWORD dwThreadId;
    DWORD dwProcessId;
    LPWSTR lpszMsg;
    BOOL fAllocated;
    DWORD dwCmd;

    /*
     * Note: fShutdown isn't used for anything in this routine!
     * They are still there because I haven't removed them: the old endtask
     * code relied on them.
     */
    UNREFERENCED_PARAMETER(fShutdown);

    /*
     * Get the process and thread that owns hwnd.
     */
    dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId);
    if (dwThreadId == 0)
        return TRUE;

    /*
     * If this is a console window, then just send the close message to
     * it, and let console clean up the processes in it.
     */
    if ((HANDLE)GetWindowLong(hwnd, GWL_HINSTANCE) == hModuleWin) {
        PostMessage(hwnd, WM_CLOSE, 0, 0);
        return TRUE;
    }

    /*
     * Find the CSR_THREAD for the window.
     */
    LeaveCrit();
    CsrLockThreadByClientId((HANDLE)dwThreadId, &pcsrtKill);
    EnterCrit();
    if (pcsrtKill == NULL)
        return TRUE;
    CsrReferenceThread(pcsrtKill);
    CsrUnlockThread(pcsrtKill);

    /*
     * If this is a WOW app, then shutdown just this wow application.
     */
    if (!fMeanKill) {
        /*
         * Find out what to do now - did the user cancel or the app cancel,
         * etc? Only allow cancelling if we are not forcing the app to
         * exit.
         */
        dwCmd = MySendEndSessionMessages(hwnd, pcsrtKill, TRUE, 0);
        switch (dwCmd) {
        case CMDEND_APPSAYSNOTOK:
            /*
             * App says not ok - this'll let taskman bring up the "are you sure?"
             * dialog to the user.
             */
            CsrDereferenceThread(pcsrtKill);
            return FALSE;

        case CMDEND_USERSAYSCANCEL:
            /*
             * User hit cancel on the timeout dialog - so the user really meant
             * it. Let taskman know everything is ok by returning TRUE.
             */
            CsrDereferenceThread(pcsrtKill);
            return TRUE;
        }
    }

    /*
     * Kill the application now.  If the thread has not been destroyed,
     * nuke the task.  If WowExitTask returns that the thread is not
     * a WOW task, terminate the process.
     */
    if (!(pcsrtKill->Flags & CSR_THREAD_DESTROYED) && !WowExitTask(pcsrtKill)) {

        /*
         * Calling ExitProcess() in the app's context will not always work
         * because the app may have .dll termination deadlocks: so the thread
         * will hang with the rest of the process. To ensure apps go away,
         * we terminate the process with NtTerminateProcess().
         *
         * Pass this special value, DBG_TERMINATE_PROCESS, which tells
         * NtTerminateProcess() to return failure if it can't terminate the
         * process because the app is being debugged.
         */
        if (!NT_SUCCESS(NtTerminateProcess(pcsrtKill->Process->ProcessHandle,
                DBG_TERMINATE_PROCESS))) {
            /*
             * If the app is being debugged, don't close it - because that can
             * cause a hang to the NtTerminateProcess() call.
             */
            lpszMsg = ServerLoadString(hModuleWin, STR_APPDEBUGGED,
                    NULL, &fAllocated);
            if (lpszMsg) {
                if (NT_SUCCESS(NtUserSetInformationThread(NtCurrentThread(),
                        UserThreadUseDesktop, &pcsrt->ThreadHandle, sizeof(HANDLE)))) {
                    HANDLE hNull = NULL;

                    LeaveCrit();
                    MessageBoxEx(NULL, lpszMsg, NULL,
                                    MB_OK | MB_SETFOREGROUND, 0);
                    EnterCrit();
                    NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop,
                            &hNull, sizeof(HANDLE));
                }
                LocalFree(lpszMsg);
            }
        } else {
            pcsrtKill->Process->Flags |= CSR_PROCESS_TERMINATED;
        }
    }
    CsrDereferenceThread(pcsrtKill);

    return TRUE;
}