Closing OpenFileDialog/SaveFileDialog

后端 未结 4 1621
星月不相逢
星月不相逢 2020-12-11 06:29

We have a requirement to close child form as part of auto logoff. We can close the child forms by iterating Application.OpenForms from the timer thread. We are not able to c

相关标签:
4条回答
  • 2020-12-11 06:44

    My answer is conceptually similar to Hans Passant's answer.

    However, using GetCurrentThreadId() as the tid parameter to EnumThreadWindows did not work for me since I was calling it from another thread. If you're doing that, then either enumerate the process' thread IDs and try each one until you find the windows you need:

    ProcessThreadCollection currentThreads = Process.GetCurrentProcess().Threads;
    foreach (ProcessThread thread in currentThreads) {
        CloseAllDialogs(thread.Id);
    }
    

    Or save off the thread IDs that do the ShowDialog to open the CommonDialog:

    threadId = GetCurrentThreadId();
    threadIds.Add(threadId);
    result = dialog.ShowDialog()
    threadIds.Remove(threadId);
    

    and then:

    foreach (int threadId in threadIds) {
        CloseAllDialogs(threadId);
    }
    

    Where CloseAllDialogs looks like:

    public void CloseAllDialogs(int threadId) {
        EnumThreadWndProc callback = new EnumThreadWndProc(checkIfHWNDPointsToWindowsDialog);
        EnumThreadWindows(threadId, callback, IntPtr.Zero);
        GC.KeepAlive(callback);
    }
    
    private bool checkIfHWNDPointsToWindowsDialog(IntPtr hWnd, IntPtr lp) {
        StringBuilder sb = new StringBuilder(260);
        GetClassName(hWnd, sb, sb.Capacity);
        if (sb.ToString() == "#32770") {
            SendMessage(hWnd, 0x0010, IntPtr.Zero, IntPtr.Zero);
        }
        return true;
    }
    
    private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
    
    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern int GetCurrentThreadId();
    
    [DllImport("user32.dll", SetLastError = true)]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
    
    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    
    0 讨论(0)
  • 2020-12-11 06:45

    This is going to require pinvoke, the dialogs are not Forms but native Windows dialogs. The basic approach is to enumerate all toplevel windows and check if their class name is "#32770", the class name for all dialogs owned by Windows. And force the dialog to close by sending the WM_CLOSE message.

    Add a new class to your project and paste the code shown below. Call DialogCloser.Execute() when the logout timer expires. Then close the forms. The code will work for MessageBox, OpenFormDialog, FolderBrowserDialog, PrintDialog, ColorDialog, FontDialog, PageSetupDialog and SaveFileDialog.

    using System;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    static class DialogCloser {
        public static void Execute() {
            // Enumerate windows to find dialogs
            EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
            EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero);
            GC.KeepAlive(callback);
        }
    
        private static bool checkWindow(IntPtr hWnd, IntPtr lp) {
            // Checks if <hWnd> is a Windows dialog
            StringBuilder sb = new StringBuilder(260);
            GetClassName(hWnd, sb, sb.Capacity);
            if (sb.ToString() == "#32770") {
                // Close it by sending WM_CLOSE to the window
                SendMessage(hWnd, 0x0010, IntPtr.Zero, IntPtr.Zero);
            }
            return true;
        }
    
        // P/Invoke declarations
        private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
        [DllImport("user32.dll")]
        private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
        [DllImport("kernel32.dll")]
        private static extern int GetCurrentThreadId();
        [DllImport("user32.dll")]
        private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    }
    
    0 讨论(0)
  • 2020-12-11 06:46

    i would not close all child forms in one thread but rather raise an event that every child form can/must subscribe to. on raise your forms can decide what to do now. clean up something, persist state, send a message to the server in the scope of your form you can access the openfiledialog and try to close that.

    0 讨论(0)
  • 2020-12-11 06:59

    [workaround] here is example:

    You should define fully transparent window ex. "TRANSP";

    Every time you need to show dialog, you need to show TRANSP and pass TRANSP as a parameter to ShowDialog method.

    When the application shuts down - call Close() Method of TRANSP window. Child dialogs will close.

        public partial class MainWindow : Window
    {
        OpenFileDialog dlg;
        TranspWnd transpWnd;
    
        public MainWindow()
        {
            InitializeComponent();
    
            Timer t = new Timer();
            t.Interval = 2500;
            t.Elapsed += new ElapsedEventHandler(t_Elapsed);
            t.Start();
        }
    
        void t_Elapsed(object sender, ElapsedEventArgs e)
        {
            Dispatcher.BeginInvoke(new Action(() =>
            {
                transpWnd.Close();
            }), null);
        }
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            transpWnd = new TranspWnd();
            transpWnd.Visibility = System.Windows.Visibility.Hidden; //doesn't works right
            transpWnd.Show();
    
            dlg = new OpenFileDialog();
            dlg.ShowDialog(transpWnd);
        }
    }
    
    0 讨论(0)
提交回复
热议问题