On Thu, Apr 6, 2017 at 7:38 PM, Kurt Eilander <web...@totalrewind.com> wrote:
> Hey all,
>
> I'm trying to get system modal functionality like the UAC dialog.
>
> According to http://developex.com/blog/system-modal-back/ the thing to do is
> to create and switch to a new desktop.
>
> Therefore, I'm doing:
>
> hDeskOld=win32service.GetThreadDesktop(win32api.GetCurrentThreadId())

SwitchDesktop affects which desktop has input focus. SetThreadDesktop
affects which desktop is used by the current thread. You need to open
a handle to the current input desktop to switch back to it at the end.

I'm far from a Tk expert. I don't know how to close out the resources
it uses to be able to call SetThreadDesktop. I'm not going to bother
figuring this out to get this working on the main thread. I'll just
create a new thread; pass it the handle for the new desktop; save the
existing input desktop; set the thread desktop; and switch the input
desktop. Then on teardown switch back to the original input desktop
and close the desktop handles.

Since I can't reliably call SetThreadDesktop to restore the worker
thread's desktop before the thread exits, there's some asynchronous
overlap when the thread and its resources haven't been destroyed yet.
To address the potential for getting ERROR_BUSY when calling
CloseDesktop from the main thread, I'm adding a retry loop that
defaults to 10 attempts, with a delay of 0.1s. It shouldn't need more
than 2 attempts.

    import sys
    import time
    import tkinter
    import threading

    import winerror
    import win32con
    import win32api
    import win32service

    def close_desktop(hDesk, numtries=10):
        for i in range(numtries):
            try:
                return hDesk.CloseDesktop()
            except win32service.error as e:
                if e.winerror != winerror.ERROR_BUSY or i == numtries - 1:
                    raise
            time.sleep(0.1)

    def dialog(hDesk, title='SysModalDialog', message='', img=None):
        hDeskInputOld = win32service.OpenInputDesktop(0, False,
                            win32con.DESKTOP_SWITCHDESKTOP)
        try:
            hDesk.SetThreadDesktop()
            hDesk.SwitchDesktop()
            try:
                root = tkinter.Tk()
                #root.mainloop()
                app = SysmodalDialog(root, title, message, img)
                app.mainloop()
            finally:
                hDeskInputOld.SwitchDesktop()
        finally:
            close_desktop(hDeskInputOld)

    def main():
        hDesk = win32service.CreateDesktop("SysModalDesktop", 0,
                win32con.GENERIC_ALL, None)
        try:
            t = threading.Thread(target=dialog, args=(hDesk,))
            t.start()
            t.join()
        finally:
            close_desktop(hDesk)
        return 0

    if __name__ == '__main__':
        sys.exit(main())
_______________________________________________
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32

Reply via email to