在 NW.JS 中从程序切换器中隐藏窗口

Posted

技术标签:

【中文标题】在 NW.JS 中从程序切换器中隐藏窗口【英文标题】:Hide window from program switcher in NW.JS 【发布时间】:2015-12-23 02:51:02 【问题描述】:

我正在使用 NW.JS (node-webkit) 编写桌面应用程序。在我的应用程序中,用户可能会打开许多​​窗口,我想将它们从程序切换器(alt+tab)和任务栏中隐藏起来。我已经找到了从任务栏隐藏窗口的选项,但找不到任何方法从程序切换器中隐藏它。甚至可能吗?或者至少可以将所有窗口归为一个(就像在 Windows 上的 Sticky Notes 中一样)?

【问题讨论】:

【参考方案1】:

这个功能可能会在某个时候出现,但从 0.12.3 版本开始,node-webkit 不提供任何用于实现工具类型窗口的接口,因此无法使用 javascript 或使用项目的包来实现这一点。 json 文件。我可以在这里想到两个选项。

1. 自己构建 node-webkit。 The guide 非常直接和全面。需要修改native_aurora_aura.cc中NativeWindowAura的构造函数,具体是这个位:

#if defined(OS_WIN)
  HWND hwnd = views::HWNDForWidget(window_->GetTopLevelWidget());
  int current_style = ::GetWindowLong(hwnd, GWL_STYLE);
  ::SetWindowLong(hwnd, GWL_STYLE, current_style | WS_CAPTION); //This is the importante line
#endif

到:

  ::SetWindowLong(hwnd, GWL_STYLE, current_style | WS_CAPTION | WS_EX_TOOLWINDOW);

请注意,这是一个简单的解决方案,它将导致 所有 新窗口默认为工具样式,并且在切换窗口时不可见。使该功能可用于清单文件或window API 将需要对几个文件进行更改。

2. 编写和部署一个启动应用程序,该应用程序加载您打包的项目(或您的项目文件夹),不断搜索具有特定标题的窗口并设置窗口样式。这是一个使用 c# 控制台应用程序的示例,但您也可以为此使用 c++ 或任何 .NET 语言:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Timers;
using System.Diagnostics;

namespace nw

   class Program
   
      const int GWL_EXSTYLE      = -0x14;
      const int WS_EX_APPWINDOW  = 0x40000;
      const int WS_EX_TOOLWINDOW = 0x80;
      const int WS_EX_COMPOSITED = 0x02000000;

      [DllImport("user32", CharSet = CharSet.Auto)]
      static extern int GetWindowLong(IntPtr hwnd, int index);

      [DllImport("User32.Dll")]
      static extern int SetWindowLong(IntPtr hwnd, int index, int newLong);

      [DllImport("user32.dll", CharSet = CharSet.Unicode)]
      static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);

      [DllImport("user32.dll", CharSet = CharSet.Unicode)]
      static extern int GetWindowTextLength(IntPtr hWnd);

      [DllImport("user32.dll")]
      static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);

      [DllImport("user32.dll")]
      static extern IntPtr SetWindowText(IntPtr HWND, string Text);

      delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);


      //------------------------------------------------------------------
      static void Main(string[] args)
      
         // Test an unpackaged app like:
         // Process.Start(<path\to\nw.exe>, <path\to\project-folder>);

         Process.Start("packaged-nw-app.js");

         Timer timer = new Timer()  Interval = 100, Enabled = true ;
         timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

         Console.ReadLine();
      


      //------------------------------------------------------------------
      static void OnTimedEvent(object source, ElapsedEventArgs e)
      
         // Find our target windows (change "nw-tool-window" to your window title)
         IEnumerable<IntPtr> windows = FindWindowsWithText("nw-tool-window");

         foreach (var window in windows)
         
            // Apply WS_EX_TOOLWINDOW to the current style
            SetWindowLong(window, GWL_EXSTYLE, (GetWindowLong(window, GWL_EXSTYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW);
            // Change title to flag as changed
            SetWindowText(window, "nw-tool-window-hidden");
         
      


      //------------------------------------------------------------------
      static string GetWindowText(IntPtr hwnd)
      
         int size = GetWindowTextLength(hwnd);

         if (size > 0)
         
            var builder = new StringBuilder(size + 1);
            GetWindowText(hwnd, builder, builder.Capacity);
            return builder.ToString();
         

         return String.Empty;
      


      //------------------------------------------------------------------
      static IEnumerable<IntPtr> FindWindows(EnumWindowsProc filter)
      
         IntPtr found = IntPtr.Zero;
         List<IntPtr> windows = new List<IntPtr>();

         EnumWindows(delegate(IntPtr wnd, IntPtr param)
         
            if (filter(wnd, param))
            
               windows.Add(wnd);
            

            return true;
         , IntPtr.Zero);

         return windows;
      


      //------------------------------------------------------------
      static IEnumerable<IntPtr> FindWindowsWithText(string titleText)
      
         return FindWindows(delegate(IntPtr wnd, IntPtr param)
         
            return GetWindowText(wnd).Contains(titleText);
         );
       
   

查找标题的代码取自here。如果你只对你的主窗口感兴趣,你可以去掉上面的大部分代码,只使用FindWindowSetWindowLong。您还应该隐藏控制台或窗口(如果您使用 Forms 或 WPF 执行此操作),有足够的信息说明如何在 SO 上完成此操作。

第二种方法有点老套,不过,我宁愿选择第一种。并且可能正确地实现它而不是硬编码并打开一个拉取请求:)

【讨论】:

谢谢,这似乎是实现它的方式。我会看看我今天是否有时间尝试一下。如果我想出一个好的解决方案,我会提出一个拉取请求,因为通过他们的 API 拥有这个功能真的很不错。【参考方案2】:

我从未使用过 NW.JS,所以这可能是完全错误的,但看起来 NM.JS 有一个 Native UI 模块。我想使用这个模块你应该能够创建本地窗口并给它们一个 WS_EX_TOOLWINDOW 样式。请参阅此答案:Best way to hide a window from the Alt-Tab program switcher。如果您只针对 Windows,这似乎是通知的最佳途径。

另一个需要考虑的想法是使用 IFRAMES 构建您的应用程序,以便只有一个本机窗口。然后您可以使用 javascript 和您自己的界面来决定显示哪些 IFRAMES。

【讨论】:

以上是关于在 NW.JS 中从程序切换器中隐藏窗口的主要内容,如果未能解决你的问题,请参考以下文章

C#窗口切换问题:如何切换回主窗体

按Alt+Tab会出现切换栏,选定某个窗口之后会切换到那个窗口,我想问的是如何能啥都不显示直接切

C# Winform多窗口间切换

如何在本机反应中从相机按钮切换到视频录制按钮

NW.JS填坑指南(解决Flash插件视频播放等故障)

如何在 KivyMD 中隐藏 MDcard 并切换到另一个?