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

时间:2015-09-25 09:43:59

标签: javascript node.js node-webkit nw.js

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

2 个答案:

答案 0 :(得分:1)

此功能可能会在某些时候出现,但是从版本0.12.3开始,node-webkit并没有为实现工具类型窗口提供任何接口,因此无法通过javascript完成此任务或使用项目的package.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上完成此操作的足够信息。

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

答案 1 :(得分:0)

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

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