【问题标题】:Getting Process Desktop获取进程桌面
【发布时间】:2015-05-13 21:41:01
【问题描述】:

作为我正在制作的项目的一部分,我使用 CreateDesktopSwitchDesktopSetThreadDesktop... 等创建和使用新桌面。

创建新桌面并切换到通过CreateProcess 创建的进程并存储句柄后,当桌面关闭时,我可以使用TerminateProcess 终止进程,以便Windows 可以删除/关闭桌面因为必须先终止桌面中的所有进程,然后才能关闭桌面。

但是,使用文件对话框的程序会打开用户在桌面上执行任意进程,例如,如果我要为此桌面创建 notepad.exe 进程,用户可以单击 File > Open 导航到 %windir% 并然后执行explorer.exe,它实际上会在桌面上打开,给它一个任务栏、开始按钮,当然还有做任何他们想做的事情的能力。

问题是当这样的事情发生并且桌面切换回主桌面时,我的程序只知道并可以终止它已经启动的进程,留下explorer.exe和桌面中剩下的任何其他进程在进程中,防止桌面被关闭。

我正在考虑使用EnumProcesses,然后为每个获取一个句柄,并希望找到一种方法来检索其桌面名称,以便我可以将其与我的进行比较并终止进程。

这是解决这个问题的正确方法吗?如果是这样,我可以使用什么 WinAPI 函数来检索进程的桌面名称?但是,如果它不是正确的方法,我可以做些什么来解决、预防或减轻这种情况?

【问题讨论】:

  • EnumDesktopWindows,但仅获取具有顶级窗口的进程可能还不够。您可能需要终止桌面上的所有进程。
  • 如果线程在当前进程中打开的桌面上运行,GetThreadDesktop 应该会成功,并且应该从进程句柄表中返回现有的桌面句柄(这就是为什么“[y]you do不需要调用CloseDesktop函数来关闭返回的句柄”)。您可以使用Tool Help library 遍历系统上的线程并创建要终止的进程句柄列表。
  • @eryksun 工作完美,遍历新桌面中的线程和进程以获取该桌面中的进程。您介意将其发布为答案,以便我投票并接受吗?
  • 我还尝试通过EnumDesktopWindowsSendMessageTimeout 优雅地退出尽可能多的进程,以向顶级窗口发送WM_CLOSE 消息。超时应该给用户一个合理的时间来确认对话。然后我会终止剩下的任何进程。

标签: windows winapi process desktop


【解决方案1】:

有几种方法可以解决您的问题。

  1. 就像@eryksun 所说,您可以使用EnumDesktopWindows 获取所有顶级窗口并将它们作为WM_CLOSE 消息发送。之后,您可以使用 WaitForSingleObjectWaitForMultipleObjects 超时,因此您可以在超时后终止它们。您可以使用WAIT_TIMEOUT 检查超时。这是python中的一个例子:
    import win32api
    import win32con
    import win32event
    import win32gui
    import win32process
    import win32service


    def closeProcessesOnDesk(deskName,timeout):
        print("try to close Processes on given Desktop")
        hwndlist=[]
        try:
            hdesk = win32service.OpenDesktop(deskName,0,False,0)
            hwndlist = hdesk.EnumDesktopWindows()
        except Exception as ex:
            print("Desktop wasn't found. {}".format(ex))
        processlist =[]
        #try to close nicely processes"
        for hwnd in hwndlist:
            # Get the window's process id's
            if win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd):
                tid, pid = win32process.GetWindowThreadProcessId(hwnd)
                handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 0, pid)
                processlist.append(handle)
            # Ask window nicely to close
                try:
                    win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
                except:
                    pass
            # Allow some time for app to close
        print("Start waiting for processes to close")
        try:
            state = win32event.WaitForMultipleObjects(processlist, True, timeout)

            if state == win32con.WAIT_TIMEOUT:
                print("processes didn't close nicely, terminate them")
        except Exception as ex:
            print("Error on closing Process. {}".format(ex))
        finally:
            for hproc in processlist:
                if hproc:
                    win32api.TerminateProcess(hproc,0)
                    win32api.CloseHandle(hproc)  

    closeProcessesOnDesk('test',2000)
  1. 由于您已创建进程的句柄,您可以使用它来终止该进程的整个进程树。在您的情况下,每个将在 notepad.exe 中以 File > Open 启动的进程也将被终止。在python中:
import subprocess


def killProcessTree(parent_pid):
    try:
        subprocess.call(['taskkill', '/F', '/T', '/PID', str(parent_pid)])
        print("Process killed: %s " % str(parent_pid))
    except Exception as ex:
        print("Process was not killed %s" % ex
  1. 您还可以创建一个具有受限权限的新用户,这样他甚至无法启动另一个进程。使用CreateProcessWithLogonWCreateProcessAsUser 以“受限用户”身份启动进程。但要小心,因为 winstation 和 Desktops 是安全对象,您必须将用户 sid 添加到桌面和 winstation 的 DACL

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多