【问题标题】:How can an application that has a not visible WinForm be restored from another application?如何从另一个应用程序恢复具有不可见 WinForm 的应用程序?
【发布时间】:2014-01-16 04:09:57
【问题描述】:

我有一个通常最小化运行的实用 WinForm 应用程序。它用于制造工厂的 PC 上。我想让应用程序在最小化时变得不可见,以防止意外关闭表单或使用某些设置。并非万无一失,只是要小心一点。

但是,我无法让应用程序的主窗体和唯一窗体重新出现,从同一应用程序的另一个实例向其发送 WM_SYSCOMMANDSC_RESTORE 消息。

我已将Resize_Event 设置为在未最小化时将Visible 设置回true

我试过SendMessagePostMessage。如果我在不将表单的 Visible 属性设置为 false 的情况下允许表单最小化或最大化,则调用会按预期工作并且目标表单会调整大小。

表单的消息泵是否未在此状态下运行,因此它忽略了消息?

我应该创建另一个线程来每隔一段时间检查一个消息队列吗?这是怎么做到的?

正在恢复表单的应用中的示例代码:

...
Process current = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName("MyApp")) { //current.ProcessName)) {
  if (process.Id != current.Id) {
    SendMessage(process.MainWindowHandle, WM_SYSCOMMAND, (IntPtr)SC_RESTORE, (IntPtr)0);
    Interaction.AppActivate(process.Id); //Most reliable way to focus target
    SetForegroundWindow(process.MainWindowHandle);
    break;
  }
}
...

恢复可见性的目标形式的代码。

  // If form is minimized then hide it
  if (WindowState == FormWindowState.Minimized) {
    this.Visible = false;
  }
  else {
    this.Visible = true;
  }

【问题讨论】:

  • 在最小化时创建托盘图标可能比让用户尝试重新启动应用程序只是为了再次显示它更好。这样做时,您将保持在同一个流程中,并且不需要处理任何 IPC 混乱。
  • 这是我考虑过的另一个想法。在那里重新打开并不那么明显。
  • @HansPassant - 是的,它基于此,但奇怪的是我无法以这种方式处理隐藏表单。
  • 该答案明确向您展示了如何恢复窗口。它不需要“句柄”,事件处理程序在进程的第一个实例中运行,因此不需要任何类型的进程互操作。 .NET 负责处理它。我不可能猜到“怪癖”可能是什么。

标签: c# winforms visibility message-queue


【解决方案1】:

我通常做的是覆盖Form.OnClosing 方法,然后继续设置e.Cancel = true。然后调用Hide() 方法,使其仍在后台运行。

为了取回应用程序,我使用named events 创建了一个单实例应用程序。您也可以使用互斥锁。请参阅此 SO anwser:How to run one instance of a c# WinForm application?

编辑 命名事件还将帮助您从另一个应用程序中打开它。就在您收到某种表演活动时,您只需将您的表格告诉Show()

【讨论】:

  • 这个问题是当窗体隐藏时 Process.MainWindowHandle 为 0。
【解决方案2】:

这不是万无一失的,但实现起来很简单。

  • 添加一个布尔值,如 m_closePrompt,您在程序首次加载时设置为 true
  • FormClosing 事件连接一个事件处理程序。

private void MdiForm_Closing(object sender, FormClosingEventArgs e) {
  if (m_closePrompt) {
    string ask = "Really Close this Application?";
    if (MessageBox.Show(ask, "Confirmation",  MessageBoxButtons.YesNo, MessageBoxIcon.Question, 0) != DialogResult.Yes) {
      e.Cancel = true;
    } else {
      m_closePrompt = false;
    }
  }
}

那至少应该会弹出系统对话框。

如果您希望关闭应用程序的其他方法(例如未处理的异常),请在关闭应用程序之前在错误处理例程中设置 m_closePrompt = false

【讨论】:

  • 哎呀。我错过了关于“来自另一个应用程序”的部分。如果这对您没有任何帮助,请告诉我,我将删除它。我想给你一个机会先看看,以防万一。
  • 这个解决方法很接近,但汉斯让我找到了正确的方向。
【解决方案3】:

Hans Passant 对我提到的question 的问题发表了评论,为我指明了正确的方向。

我的最终代码如下所示。

using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;   // Add reference to Microsoft.VisualBasic

namespace MyApp
{
  class Program : WindowsFormsApplicationBase 
  {
     /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
      var app = new Program();
      app.Run(args);
    }
    public Program()
    {
      this.IsSingleInstance = true;
      this.EnableVisualStyles = true;
      this.MainForm = new fMain();
    }
    protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    {
      if (this.MainForm.WindowState == FormWindowState.Minimized) {
        this.MainForm.Show();     // Unhide if hidden
        this.MainForm.WindowState = FormWindowState.Normal; //Restore
      }
      this.MainForm.Activate();
    }
  }

}

【讨论】:

    猜你喜欢
    • 2019-10-30
    • 2011-05-19
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多