关于Winforms:C#Force Form Focus

关于Winforms:C#Force Form Focus

C# Force Form Focus

因此,在问这个问题之前,我确实搜索过Google和SO。基本上,我有一个DLL,其中已编译了一个窗体。该表格将用于在屏幕上显示信息。最终它将是异步的,并且在dll中公开了很多自定义项。现在,我只希望它正确显示。我遇到的问题是,我通过在Powershell会话中加载dll来使用它。因此,当我尝试显示表单并将其放到顶部并获得焦点时,在其他所有应用程序上显示都没有问题,但是我一生都无法将其显示在Powershell窗口中。这是我当前用来尝试显示的代码。我敢肯定,一旦我弄清了它的大部分,就不需要了,这只是我通过google找到的所有东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
CLass Blah
{
        [DllImport("user32.dll", EntryPoint ="SystemParametersInfo")]
        public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni);

        [DllImport("user32.dll", EntryPoint ="SetForegroundWindow")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("User32.dll", EntryPoint ="ShowWindowAsync")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
        private const int WS_SHOWNORMAL = 1;

    public void ShowMessage(string msg)
    {
            MessageForm msgFrm = new MessageForm();
            msgFrm.lblMessage.Text ="FOO";
            msgFrm.ShowDialog();
            msgFrm.BringToFront();
            msgFrm.TopMost = true;
            msgFrm.Activate();

            SystemParametersInfo((uint)0x2001, 0, 0, 0x0002 | 0x0001);
            ShowWindowAsync(msgFrm.Handle, WS_SHOWNORMAL);
            SetForegroundWindow(msgFrm.Handle);
            SystemParametersInfo((uint)0x2001, 200000, 200000, 0x0002 | 0x0001);
    }
}

正如我说的那样,我可以确定大部分内容不是必需的,甚至是完全错误的,我只是想展示自己尝试过的东西。另外,正如我所提到的,我计划在某个时候异步显示它,我怀疑这最终会需要一个单独的线程。将表单拆分成自己的线程是否会使它更容易集中在Powershell会话上?

@Joel,感谢您的信息。这是我根据您的建议尝试的:

1
2
3
4
msgFrm.ShowDialog();
msgFrm.BringToFront();
msgFrm.Focus();
Application.DoEvents();

该表格仍在Powershell会话下出现。我将继续研究线程。我之前已经生成了线程,但从未在父线程与子线程进行通讯的地方生成过线程,因此我们将了解它的运行情况。

到目前为止,所有想法都得到了人们的认可。

好的,线程解决了这个问题。 @Quarrelsome,我确实尝试了这两种方法。没有一个(也没有一起)。我对使用线程有什么弊端感到好奇?我没有使用Application.Run,??但是我还没有遇到任何问题。我正在使用一个父线程和子线程都可以访问的介体类。在该对象中,我使用ReaderWriterLock锁定一个属性,该属性表示要在子线程创建的表单上显示的消息。父级锁定该属性,然后编写应显示的内容。子线程锁定该属性,并读取它应将表单上的标签更改为的内容。孩子必须在轮询间隔(我默认将其设置为500ms)上执行此操作,这并不是我真正满意的事情,但是我找不到一种事件驱动的方式来让孩子线程知道属性已更改,所以我我坚持投票。


这是我几年使用一种或另一种形式的一些代码。在另一个应用程序中弹出窗口有一些技巧。有了窗口句柄后,请执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
      if (IsIconic(hWnd))
        ShowWindowAsync(hWnd, SW_RESTORE);

      ShowWindowAsync(hWnd, SW_SHOW);

      SetForegroundWindow(hWnd);

      // Code from Karl E. Peterson, www.mvps.org/vb/sample.htm
      // Converted to Delphi by Ray Lischner
      // Published in The Delphi Magazine 55, page 16
      // Converted to C# by Kevin Gale
      IntPtr foregroundWindow = GetForegroundWindow();
      IntPtr Dummy = IntPtr.Zero;

      uint foregroundThreadId = GetWindowThreadProcessId(foregroundWindow, Dummy);
      uint thisThreadId       = GetWindowThreadProcessId(hWnd, Dummy);

      if (AttachThreadInput(thisThreadId, foregroundThreadId, true))
      {
        BringWindowToTop(hWnd); // IE 5.5 related hack
        SetForegroundWindow(hWnd);
        AttachThreadInput(thisThreadId, foregroundThreadId, false);
      }

      if (GetForegroundWindow() != hWnd)
      {
        // Code by Daniel P. Stasinski
        // Converted to C# by Kevin Gale
        IntPtr Timeout = IntPtr.Zero;
        SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, Timeout, 0);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Dummy, SPIF_SENDCHANGE);
        BringWindowToTop(hWnd); // IE 5.5 related hack
        SetForegroundWindow(hWnd);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Timeout, SPIF_SENDCHANGE);
      }

我不会发布整个单元,因为它会执行其他不相关的事情
但这里是上述代码的常量和导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//Win32 API calls necesary to raise an unowned processs main window

[DllImport("user32.dll")]

private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll")]
static extern bool BringWindowToTop(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, Int32 nMaxCount);
[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, ref Int32 lpdwProcessId);
[DllImport("User32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);

private const int SW_HIDE = 0;
private const int SW_SHOWNORMAL = 1;
private const int SW_NORMAL = 1;
private const int SW_SHOWMINIMIZED = 2;
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_MAXIMIZE = 3;
private const int SW_SHOWNOACTIVATE = 4;
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_SHOWMINNOACTIVE = 7;
private const int SW_SHOWNA = 8;
private const int SW_RESTORE = 9;
private const int SW_SHOWDEFAULT = 10;
private const int SW_MAX = 10;

private const uint SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
private const uint SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
private const int  SPIF_SENDCHANGE = 0x2;


我也无法激活并将窗口置于前台。这是最终为我工作的代码。我不确定是否能解决您的问题。

基本上,先调用ShowWindow()然后再调用SetForegroundWindow()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.Diagnostics;
using System.Runtime.InteropServices;

// Sets the window to be foreground
[DllImport("User32")]
private static extern int SetForegroundWindow(IntPtr hwnd);

// Activate or minimize a window
[DllImportAttribute("User32.DLL")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_RESTORE = 9;

private void ActivateApplication(string briefAppName)
{
    Process[] procList = Process.GetProcessesByName(briefAppName);

    if (procList.Length > 0)
    {
        ShowWindow(procList[0].MainWindowHandle, SW_RESTORE);
        SetForegroundWindow(procList[0].MainWindowHandle);
    }
}

TopMost = true;
。启用() ?

那些有什么好处吗?

将其拆分为自己的线程有点邪恶,因为如果不使用Application.Run调用它,它将无法正常工作,这将吞噬线程。在最坏的情况下,我想您可以将其分离到另一个进程中,并通过磁盘或WCF进行通信。


ShowDialog()的窗口行为是否与Show()不同?

如果您尝试了怎么办:

1
2
3
msgFrm.Show();
msgFrm.BringToFront();
msgFrm.Focus();

以下解决方案应满足您的要求:

  • 程序集可以加载到PowerShell中并实例化主类
  • 在此实例上调用ShowMessage方法时,将显示并激活一个新窗口
  • 如果您多次调用ShowMessage,则同一窗口将更新其标题文本并被激活
  • 要停止使用该窗口,请调用Dispose方法
  • 步骤1:让我们创建一个临时工作目录(您自然可以使用自己的目录)

    1
    2
    3
    (powershell.exe)
    mkdir C:\\TEMP\\PshWindow
    cd C:\\TEMP\\PshWindow

    步骤2:现在,我们定义将在PowerShell中与之交互的类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    // file 'InfoProvider.cs' in C:\\TEMP\\PshWindow
    using System;
    using System.Threading;
    using System.Windows.Forms;

    namespace PshWindow
    {
        public sealed class InfoProvider : IDisposable
        {
            public void Dispose()
            {
                GC.SuppressFinalize(this);
                lock (this._sync)
                {
                    if (!this._disposed)
                    {
                        this._disposed = true;
                        if (null != this._worker)
                        {
                            if (null != this._form)
                            {
                                this._form.Invoke(new Action(() => this._form.Close()));
                            }
                            this._worker.Join();
                            this._form = null;
                            this._worker = null;
                        }
                    }
                }
            }

            public void ShowMessage(string msg)
            {
                lock (this._sync)
                {
                    // make sure worker is up and running
                    if (this._disposed) { throw new ObjectDisposedException("InfoProvider"); }
                    if (null == this._worker)
                    {
                        this._worker = new Thread(() => (this._form = new MyForm(this._sync)).ShowDialog()) { IsBackground = true };
                        this._worker.Start();
                        while (this._form == null || !this._form.Created)
                        {
                            Monitor.Wait(this._sync);
                        }
                    }

                    // update the text
                    this._form.Invoke(new Action(delegate
                    {
                        this._form.Text = msg;
                        this._form.Activate();
                    }));
                }
            }

            private bool _disposed;
            private Form _form;
            private Thread _worker;
            private readonly object _sync = new object();
        }
    }

    以及将显示的表格:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    // file 'MyForm.cs' in C:\\TEMP\\PshWindow
    using System;
    using System.Drawing;
    using System.Threading;
    using System.Windows.Forms;

    namespace PshWindow
    {
        internal sealed class MyForm : Form
        {
            public MyForm(object sync)
            {
                this._sync = sync;
                this.BackColor = Color.LightGreen;
                this.Width = 200;
                this.Height = 80;
                this.FormBorderStyle = FormBorderStyle.SizableToolWindow;
            }

            protected override void OnShown(EventArgs e)
            {
                base.OnShown(e);
                this.TopMost = true;

                lock (this._sync)
                {
                    Monitor.PulseAll(this._sync);
                }
            }

            private readonly object _sync;
        }
    }

    步骤3:让我们编译程序集...

    1
    2
    (powershell.exe)
    csc /out:PshWindow.dll /target:library InfoProvider.cs MyForm.cs

    步骤4:...并在PowerShell中加载程序集以使其有趣:

    1
    2
    3
    4
    (powershell.exe)
    [System.Reflection.Assembly]::LoadFile('C:\\TEMP\\PshWindow\\PshWindow.dll')
    $a = New-Object PshWindow.InfoProvider
    $a.ShowMessage('Hello, world')

    现在应该弹出一个绿色的窗口,标题为" Hello,world"。如果您重新激活PowerShell窗口并输入:

    1
    $a.ShowMessage('Stack overflow')

    窗口的标题应更改为"堆栈溢出",并且窗口应再次处于活动状态。

    要停止使用我们的窗口,请处置该对象:

    1
    $a.Dispose()

    此解决方案在Windows XP SP3 x86和Windows Vista SP1 x64中均可以正常工作。如果对该解决方案的工作方式有疑问,我可以通过详细讨论来更新此条目。目前,我希望代码能不言自明。


    非常感谢。
    我想我把它缩短了一些,这是我放在单独线程上的内容,而且似乎工作正常。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    private static void StatusChecking()
    {
        IntPtr iActiveForm = IntPtr.Zero, iCurrentACtiveApp = IntPtr.Zero;
        Int32 iMyProcID = Process.GetCurrentProcess().Id, iCurrentProcID = 0;
        IntPtr iTmp = (IntPtr)1;

        while (bIsRunning)
        {
            try
            {
                Thread.Sleep(45);
                if (Form.ActiveForm != null)
                {
                    iActiveForm = Form.ActiveForm.Handle;
                }
                iTmp = GetForegroundWindow();
                if (iTmp == IntPtr.Zero) continue;
                GetWindowThreadProcessId(iTmp, ref iCurrentProcID);
                if (iCurrentProcID == 0)
                {
                    iCurrentProcID = 1;
                    continue;
                }
                if (iCurrentProcID != iMyProcID)
                {
                    SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, IntPtr.Zero, 0);
                    SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, IntPtr.Zero, SPIF_SENDCHANGE);
                    BringWindowToTop(iActiveForm);
                    SetForegroundWindow(iActiveForm);
                }
                else iActiveForm = iTmp;
            }
            catch (Exception ex)
            {
                Definitions.UnhandledExceptionHandler(ex, 103106);
            }
        }
    }

    我不介意定义。


    您不只是希望对话框成为调用表单的子级吗?

    为此,您需要在调用窗口中输入通行证,
    使用ShowDialog(IWin32Window owner)方法。


    您不需要为此导入任何win32函数。如果.Focus()不够,则表单还应具有.BringToFront()方法供您使用。如果失败,则可以将其.TopMost属性设置为true。您不想永远将其保留为真,因此请调用Application.DoEvents,以便表单可以处理该消息并将其设置回false。


    推荐阅读

      linux显示之前的命令?

      linux显示之前的命令?,系统,信息,命令,地址,服务,环境,数据,标准,数字,不了,l

      linux命令实时显示?

      linux命令实时显示?,系统,实时,时间,信息,情况,命令,对比,电脑,名称,一致,lin

      linux交叉编译命令?

      linux交叉编译命令?,工具,平台,位置,网上,环境,基础,代码,编译器,路径,目标,

      linux编译源代码命令?

      linux编译源代码命令?,工具,代码,百度,最新,环境,项目,系统,电脑,密码,内核,l

      linux编译时显示命令?

      linux编译时显示命令?,系统,基础,工具,代码,百度,下来,网上,命令,内核,文件,L

      linux只能命令行编译?

      linux只能命令行编译?,系统,代码,工具,软件,密码,平台,项目,设计,最新,设备,L

      linux显示运行命令?

      linux显示运行命令?,系统,服务,状态,信息,工具,数据,电脑,标准,管理,时间,如

      显示linux网卡命令行?

      显示linux网卡命令行?,系统,信息,工具,网络,服务,电脑,网卡,技术指标,地址,

      linux命令显示内容?

      linux命令显示内容?,标准,系统,数据,命令,百度,实时,时间,信息,文件,内容,lin

      linux常用显示命令?

      linux常用显示命令?,工作,地址,系统,信息,管理,命令,目录,标准,功能,常用命

      linux命令行编译c?

      linux命令行编译c?,代码,环境,系统,工具,平台,终端,程序,编辑,文件,源程序,在

      linux用命令显示账号?

      linux用命令显示账号?,密码,系统,信息,地址,电脑,名字,用户,命令,用户名,用

      linux命令行同步显示?

      linux命令行同步显示?,地址,工具,系统,数据,工作,时间,命令,综合,网址,信息,L

      linux命令显示窗口?

      linux命令显示窗口?,系统,工具,首页,终端,密码,命令,窗口,界面,桌面,选项,lin

      linux分页显示命令?

      linux分页显示命令?,工具,通信,命令,数据,信息,管道,标准,位置,一致,系统,lin

      linux中如何编译命令?

      linux中如何编译命令?,系统,代码,基础,暂停,环境,工具,百度,命令,文件,终端,

      linux中ps命令显示?

      linux中ps命令显示?,系统,信息,状态,进程,命令,多地,软件,工作,基础,报告,lin

      linux命令逐页显示?

      linux命令逐页显示?,系统,工作,地址,命令,网上,信息,百度,基础,标准,内容,在l

      linux显示内核命令?

      linux显示内核命令?,地址,发行,信息,工具,电脑,系统,名称,内核,版本,状态,如

      显示等号linux命令?

      显示等号linux命令?,工作,地址,信息,系统,命令,目录,标准,管理,基础,常用命