【问题标题】:Make minimized/system tray application gui visible from c#使最小化/系统托盘应用程序 gui 从 c# 可见
【发布时间】:2015-12-26 03:05:57
【问题描述】:

我有一个 Windows 窗体应用程序,它可以打开另一个供应商的应用程序。如果供应商的应用程序没有运行,我的代码会打开它并按预期显示。但是,如果供应商的应用程序已经最小化或在系统托盘中运行,那么当我调用Process.Start() 时,我无法使其可见。有没有办法使当前正在运行的应用程序可见/显示,无论它是最小化还是在系统托盘中?

这是我打开另一个应用程序的代码,它仅在VendorProgram.exe 未运行时才有效。如果VendorProgram.exe 正在运行但最小化它不会使其可见/显示,这就是我需要的。

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "C:\\Program Files (x86)\\VendorProgram.exe";
startInfo.WindowStyle = ProcessWindowStyle.Normal;


Process p = Process.Start(startInfo);

编辑:如果不清楚,我不是要让应用程序自行打开,而是要从我的应用程序中打开一个单独的供应商应用程序。

【问题讨论】:

  • 当外部应用程序位于 托盘(不是任务栏)时,没有标准的方法可以“显示自己”...
  • @Idle_Mind “没有标准的方式”是指.net/c# 不可能吗?
  • 否...在 Windows 本身中,没有简单或万无一失的方法可以从托盘“恢复”应用程序。当您使用托盘图标时显示的窗口/表单可能与最初启动应用程序时显示的表单相同,也可能不同;该应用程序可能会创建表单的新实例。换句话说,主窗体和托盘图标不一定相互绑定。据我所知,也没有 Windows 消息可以发送到托盘图标以使其“恢复”...

标签: c# .net winforms process


【解决方案1】:

首先,您有点想重新发明轮子。正如 Steve 在 cmets 中指出的那样,已经有实现单实例应用程序的内置方法,例如 Mutex

然而,“当它被最小化到托盘时显示”部分是棘手的。

您可以遍历正在运行的进程以找到您的进程,然后可选择启动一个新进程,或调用已经运行的进程。这需要一点 p/invoke 魔法:

[DllImport("user32.dll")]
private static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("user32.dll")]
private static extern Boolean SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);

var bFound = false;
foreach (var proc in Process.GetProcesses())
{
    if (proc.ProcessName.Equals("YourProcessName"))
    {
        var window = FindWindow(null, proc.MainWindowTitle);
        if (!window.Equals(IntPtr.Zero))
        {
            //Mixed results...this might be redundant
            SetForegroundWindow(window);
            ShowWindow(window, 1);  //SW_NORMAL
            bFound =true;
        }
    }
}

if (!bFound)
{
    var startInfo = new ProcessStartInfo();
    startInfo.CreateNoWindow = false;
    startInfo.UseShellExecute = false;
    startInfo.FileName = "C:\\Program Files (x86)\\Program.exe";
    startInfo.WindowStyle = ProcessWindowStyle.Normal;
    Process.Start(startInfo);
}

【讨论】:

  • 我只是想从 c# 打开正在运行的应用程序的 gui,而不是重新发明轮子。您的示例看起来很有希望,但无论是最小化还是在系统托盘中,它都没有打开正在运行的进程的形式。 SetForegroundShowWindow 什么也没做。
  • 您可以尝试不使用window 变量,而是用proc.MainWindowHandle 替换它的用法。 FindWindow 将找到第一个匹配项,可能它返回了错误的句柄。
  • MainWindowHandle 也没有这样做。
【解决方案2】:

我找到了this,它帮助我完成了我需要的工作。

诀窍是在FindWindow() 而不是process.MainWindowTitle 中使用正确的窗口名称。显然,process.MainWindowTitle 带回了应用程序创建的第一个窗口。这有时可能会奏效,但并非总是如此。我需要将最小化的实际窗口的名称放在系统托盘中。以记事本为例,如果标题为my file - Notepad,则需要在FindWindow 中输入。这看起来很笨拙,但每次都对我有用。记事本不是我要打开的应用程序,但它是例如。

这行不通

foreach (var proc in Process.GetProcesses()) {
    if (proc.ProcessName.Equals("Notepad"))
    {
      IntPtr window = FindWindow(null, proc.MainWindowTitle);    
      ShowWindow(hWnd, 1);
      break;
    }
 }

这样

  IntPtr window = FindWindow(null, "my file - Notepad");   
  ShowWindow(hWnd, 1); 

【讨论】:

    【解决方案3】:

    你尝试过使用

    [DllImport("user32.dll")]
    private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
    

    而不是“ShowWindow(IntPtr hWnd, int nCmdShow)”?

    【讨论】:

      猜你喜欢
      • 2011-11-29
      • 1970-01-01
      • 2015-01-31
      • 2022-10-16
      • 2017-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多