[ACCEPTED]-Closing OpenFileDialog/SaveFileDialog-winforms

Accepted answer
Score: 15

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

Add 5 a new class to your project and paste the 4 code shown below. Call DialogCloser.Execute() when 3 the logout timer expires. Then close the forms. The 2 code will work for MessageBox, OpenFormDialog, FolderBrowserDialog, PrintDialog, ColorDialog, FontDialog, PageSetupDialog 1 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);
}
Score: 1

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

Score: 0

[workaround] here is example:

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

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

When the application 2 shuts down - call Close() Method of TRANSP 1 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);
    }
}
Score: 0

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

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

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

Or save 2 off the thread IDs that do the ShowDialog to open 1 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);

More Related questions