6

自動ログオフの一部として、子フォームを閉じる必要があります。タイマー スレッドから Application.OpenForms を繰り返すことで、子フォームを閉じることができます。OpenFileDialog がリストされていないため、Application.OpenForms を使用して OpenFileDialog/SaveFileDialog を閉じることができません。

OpenFileDialog と CloseFileDialog を閉じるにはどうすればよいですか?

4

4 に答える 4

15

これには pinvoke が必要です。ダイアログはフォームではなく、ネイティブの Windows ダイアログです。基本的なアプローチは、すべてのトップレベル ウィンドウを列挙し、それらのクラス名が "#32770" (Windows が所有するすべてのダイアログのクラス名) であるかどうかを確認することです。WM_CLOSE メッセージを送信して、ダイアログを強制的に閉じます。

プロジェクトに新しいクラスを追加し、以下に示すコードを貼り付けます。ログアウト タイマーが切れたら、DialogCloser.Execute() を呼び出します。 その後、フォームを閉じます。このコードは、MessageBox、OpenFormDialog、FolderBrowserDialog、PrintDialog、ColorDialog、FontDialog、PageSetupDialog、および 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);
}
于 2012-08-23T12:58:53.723 に答える
1

1 つのスレッドですべての子フォームを閉じるのではなく、すべての子フォームがサブスクライブできる/サブスクライブする必要があるイベントを発生させます。フォームをレイズすると、今何をすべきかを決定できます。何かをクリーンアップし、状態を保持し、フォームのスコープ内でサーバーにメッセージを送信すると、openfiledialog にアクセスして、それを閉じようとすることができます。

于 2012-08-23T11:42:18.653 に答える
0

[回避策] 以下に例を示します。

完全に透明なウィンドウ ex を定義する必要があります。"トランス";

ダイアログを表示する必要があるたびに、TRANSP を表示し、TRANSP をパラメーターとして ShowDialog メソッドに渡す必要があります。

アプリケーションがシャットダウンしたら、TRANSP ウィンドウの 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);
    }
}
于 2012-08-23T13:03:17.600 に答える
0

私の答えは、ハンス・パッサントの答えと概念的に似ています。

ただし、別のスレッドから呼び出していたためGetCurrentThreadId()tidパラメーターとして使用しEnumThreadWindowsても機能しませんでした。それを行っている場合は、プロセスのスレッド ID を列挙し、必要なウィンドウが見つかるまでそれぞれを試してください。

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

ShowDialogまたは、開くために実行するスレッド ID を保存しますCommonDialog

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

その後:

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

CloseAllDialogsのようになります。

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);
于 2019-01-15T23:52:32.040 に答える