【问题标题】:Closing the Windows 8 Charm Bar关闭 Windows 8 Charm Bar
【发布时间】:2015-11-26 17:12:01
【问题描述】:

我有一个 Surface Pro,我需要将其“锁定”为一种 Kiosk 模式。我知道“信息亭模式”的更新正在进行中。但是我需要在此之前执行此操作。

我在整个互联网上进行了搜索,但您似乎无法通过在 屏幕上滑动来禁用 Charm 栏。我找到了禁用触控板的方法。但不幸的是,由于这款平板电脑将在没有键盘的情况下使用,我需要禁用 Charm 栏。

我的新想法是将整个 Charm bar HWND 移出屏幕数千像素,或者,可以在其上设置一个 windows 样式,使其不出现。我尝试使用 Spy++ 和基于自定义 EnumWindows 的控制台应用程序来为我提供一些窗口句柄。但是我无法让 Charm 栏保持足够长的时间以使它们生效。

所以我的问题是:如何在 Windows 8 中找到 Charm Bar 的窗口句柄 (HWND)?或者,我怎样才能以其他方式获得对 Charm 栏的引用,以便向其抛出 SetWindowLongSetWindowPos

【问题讨论】:

    标签: c# c++ windows-8 windows-rt


    【解决方案1】:

    事实上,我已经找到了一种方法来做到这一点(显然,没有其他人有:/)。

    对于那些想知道的人,“Start8”和“SkipMetroSuite”等软件轮询按键以停止 Charm Bar。他们从字面上模拟按键以在紧密循环中关闭它。

    我找到了(我认为是)更好的方法。

    首先...一些 WinAPI 函数:

    using System.Runtime.InteropServices;
    ....
    
    private enum WindowShowStyle : uint
    {  // find more info at http://stackoverflow.com/a/8210120/1245420
       Hide = 0, ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
       ShowNormalNoActvate = 4, Show = 5, Minimize = 6, ShowNoActivate = 8,
       Restore = 9, ShowDefault = 10, ForceMinimized = 11
    }
    
    [DllImport("user32.dll", SetLastError = true)]
    static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);
    
    [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
    static extern System.IntPtr FindWindowByCaption(System.IntPtr ZeroOnly, string lpWindowName);
    
    [DllImport("user32.dll")]
    static extern bool ShowWindow(System.IntPtr hWnd, WindowShowStyle nCmdShow);
    

    所以首先要解决的问题是魅力栏。这个窗口的标题原来是Charm Bar。产生一个不断寻找这个窗口并隐藏它的线程效果很好。所以我产生了一个线程,并不断地轮询它:

    System.Threading.Tasks.Task.Factory.StartNew(() => {
        while (true) {
            System.IntPtr hWndCharmBar = FindWindowByCaption(System.IntPtr.Zero, "Charm Bar");
            ShowWindow(hWndCharmBar, 0);
            System.Threading.Thread.Sleep(100); // sleep for a bit
        }
    });
    

    这很好用,并且在关闭应用程序时还可以让 Charm Bar 继续工作。 Thread.Sleep 用于阻止线程破坏 CPU - 但延迟也允许 Charm Bar 出现一瞬间。我还没有成功打开魅力栏并在线程再次隐藏之前足够快地按下按钮,所以这很好。降低睡眠时间显然会加快速度。

    Windows 8 的另一个问题是,如果您有某种滑块(在我的应用程序中,我有一个包含画廊图像的 ListBox),那么您实际上可以滑动到屏幕的一侧...按住你的手指在那里,然后访问任务栏...

    所以..下一部分是关闭任务栏:

    IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
    ShowWindow(hWndTray, 0);
    

    ..然后我在应用关闭时再次显示它:

    IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
    ShowWindow(hWndTray, 1);
    

    从功能上讲,这就是我的应用所需要的全部内容。希望对某人有所帮助。

    【讨论】:

    • 你的while循环会吃掉cpu。希望您不要使用电池运行 :-) 此外,NativeHWNDHost 是一个常见的类名,并非特定于魅力栏。您应该添加其他检查以确保它确实是您想要的窗口。
    • 你是对的。事实上,我很兴奋,上面的方法奏效了,我有点过火了。我很快就会用我的新版本更新它!
    • @SimonMourier 感谢您的 cmets。我已经更新了我的新版本:)
    • 得到一些基于事件的方法来检测窗口何时打开(然后你可以检查它是否是魅力栏)
    • 谢谢!这是迄今为止唯一有效的解决方案,但是我如何找到其他窗口的标题或类名,例如当您将鼠标悬停在边缘附近时弹出的“热角”、“左侧栏”和“开始按钮” .因为我也需要摆脱那些!
    【解决方案2】:

    我还想指出,时钟包含在标题为“时钟和日期”的窗口中。

    IntPtr hWndCharmClock = FindWindowByCaption(IntPtr.Zero, "Clock and Date");
    

    我做了一个小应用程序来切换魅力栏:https://bitbucket.org/darkwingduck/charmsbartoggle/overview

    【讨论】:

      【解决方案3】:

      这是在使用 SHGetPropertyStoreForWindow 互操作最大化应用程序时禁用超级按钮栏的方法。应该很容易转换为 C#:

      Imports System.Runtime.InteropServices
      Imports System.Runtime.CompilerServices
      
      Public Class EdgeGestureUtil
      
          Private Shared DISABLE_TOUCH_SCREEN As Guid = New Guid("32CE38B2-2C9A-41B1-9BC5-B3784394AA44")
          Private Shared IID_PROPERTY_STORE As Guid = New Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")
          Private Shared VT_BOOL As Short = 11
      
      #Region "Structures"
      
          <StructLayout(LayoutKind.Sequential, Pack:=4)> _
          Public Structure PropertyKey
              Public Sub New(guid As Guid, pid As UInt32)
                  fmtid = guid
                  Me.pid = pid
              End Sub
      
              <MarshalAs(UnmanagedType.Struct)> _
              Public fmtid As Guid
              Public pid As UInteger
          End Structure
      
          <StructLayout(LayoutKind.Explicit)> _
          Public Structure PropVariant
              <FieldOffset(0)> _
              Public vt As Short
              <FieldOffset(2)> _
              Private wReserved1 As Short
              <FieldOffset(4)> _
              Private wReserved2 As Short
              <FieldOffset(6)> _
              Private wReserved3 As Short
              <FieldOffset(8)> _
              Private cVal As SByte
              <FieldOffset(8)> _
              Private bVal As Byte
              <FieldOffset(8)> _
              Private iVal As Short
              <FieldOffset(8)> _
              Public uiVal As UShort
              <FieldOffset(8)> _
              Private lVal As Integer
              <FieldOffset(8)> _
              Private ulVal As UInteger
              <FieldOffset(8)> _
              Private intVal As Integer
              <FieldOffset(8)> _
              Private uintVal As UInteger
              <FieldOffset(8)> _
              Private hVal As Long
              <FieldOffset(8)> _
              Private uhVal As Long
              <FieldOffset(8)> _
              Private fltVal As Single
              <FieldOffset(8)> _
              Private dblVal As Double
              <FieldOffset(8)> _
              Public boolVal As Boolean
              <FieldOffset(8)> _
              Private scode As Integer
              'CY cyVal;
              <FieldOffset(8)> _
              Private [date] As DateTime
              <FieldOffset(8)> _
              Private filetime As System.Runtime.InteropServices.ComTypes.FILETIME
              'CLSID* puuid;
              'CLIPDATA* pclipdata;
              'BSTR bstrVal;
              'BSTRBLOB bstrblobVal;
              <FieldOffset(8)> _
              Private blobVal As Blob
              'LPSTR pszVal;
              <FieldOffset(8)> _
              Private pwszVal As IntPtr
              'LPWSTR 
              'IUnknown* punkVal;
              'IDispatch* pdispVal;
              '        IStream* pStream;
              '        IStorage* pStorage;
              '        LPVERSIONEDSTREAM pVersionedStream;
              '        LPSAFEARRAY parray;
              '        CAC cac;
              '        CAUB caub;
              '        CAI cai;
              '        CAUI caui;
              '        CAL cal;
              '        CAUL caul;
              '        CAH cah;
              '        CAUH cauh;
              '        CAFLT caflt;
              '        CADBL cadbl;
              '        CABOOL cabool;
              '        CASCODE cascode;
              '        CACY cacy;
              '        CADATE cadate;
              '        CAFILETIME cafiletime;
              '        CACLSID cauuid;
              '        CACLIPDATA caclipdata;
              '        CABSTR cabstr;
              '        CABSTRBLOB cabstrblob;
              '        CALPSTR calpstr;
              '        CALPWSTR calpwstr;
              '        CAPROPVARIANT capropvar;
              '        CHAR* pcVal;
              '        UCHAR* pbVal;
              '        SHORT* piVal;
              '        USHORT* puiVal;
              '        LONG* plVal;
              '        ULONG* pulVal;
              '        INT* pintVal;
              '        UINT* puintVal;
              '        FLOAT* pfltVal;
              '        DOUBLE* pdblVal;
              '        VARIANT_BOOL* pboolVal;
              '        DECIMAL* pdecVal;
              '        SCODE* pscode;
              '        CY* pcyVal;
              '        DATE* pdate;
              '        BSTR* pbstrVal;
              '        IUnknown** ppunkVal;
              '        IDispatch** ppdispVal;
              '        LPSAFEARRAY* pparray;
              '        PROPVARIANT* pvarVal;
              '        
      
              ''' <summary>
              ''' Helper method to gets blob data
              ''' </summary>
              Private Function GetBlob() As Byte()
                  Dim Result As Byte() = New Byte(blobVal.Length - 1) {}
                  Marshal.Copy(blobVal.Data, Result, 0, Result.Length)
                  Return Result
              End Function
      
              ''' <summary>
              ''' Property value
              ''' </summary>
              Public ReadOnly Property Value() As Object
                  Get
                      Dim ve As VarEnum = vt
                      Select Case ve
                          Case VarEnum.VT_I1
                              Return bVal
                          Case VarEnum.VT_I2
                              Return iVal
                          Case VarEnum.VT_I4
                              Return lVal
                          Case VarEnum.VT_I8
                              Return hVal
                          Case VarEnum.VT_INT
                              Return iVal
                          Case VarEnum.VT_UI4
                              Return ulVal
                          Case VarEnum.VT_LPWSTR
                              Return Marshal.PtrToStringUni(pwszVal)
                          Case VarEnum.VT_BLOB
                              Return GetBlob()
                      End Select
                      Throw New NotImplementedException("PropVariant " + ve.ToString())
                  End Get
              End Property
          End Structure
      
          Friend Structure Blob
              Public Length As Integer
              Public Data As IntPtr
      
              'Code Should Compile at warning level4 without any warnings, 
              'However this struct will give us Warning CS0649: Field [Fieldname] 
              'is never assigned to, and will always have its default value
              'You can disable CS0649 in the project options but that will disable
              'the warning for the whole project, it's a nice warning and we do want 
              'it in other places so we make a nice dummy function to keep the compiler
              'happy.
              Private Sub FixCS0649()
                  Length = 0
                  Data = IntPtr.Zero
              End Sub
          End Structure
      
      #End Region
      
      #Region "Interfaces"
      
          <ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
          Interface IPropertyStore
              <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
              Sub GetCount(<Out> ByRef cProps As UInteger)
      
              <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
              Sub GetAt(<[In]> iProp As UInteger, ByRef pkey As PropertyKey)
      
              <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
              Sub GetValue(<[In]> ByRef key As PropertyKey, ByRef pv As PropVariant)
      
              <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
              Sub SetValue(<[In]> ByRef key As PropertyKey, <[In]> ByRef pv As PropVariant)
      
              <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
              Sub Commit()
      
              <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
              Sub Release()
          End Interface
      
      #End Region
      
      #Region "Methods"
      
          <DllImport("shell32.dll", SetLastError:=True)> _
          Private Shared Function SHGetPropertyStoreForWindow(handle As IntPtr, ByRef riid As Guid, ByRef propertyStore As IPropertyStore) As Integer
          End Function
      
          Public Shared Sub EnableEdgeGestures(ByVal hwnd As IntPtr, ByVal enable As Boolean)
              Dim pPropStore As IPropertyStore = Nothing
              Dim hr As Integer
              hr = SHGetPropertyStoreForWindow(hwnd, IID_PROPERTY_STORE, pPropStore)
              If hr = 0 Then
                  Dim propKey As New PropertyKey
                  propKey.fmtid = DISABLE_TOUCH_SCREEN
                  propKey.pid = 2
                  Dim var As New PropVariant
                  var.vt = VT_BOOL
                  var.boolVal = enable
                  pPropStore.SetValue(propKey, var)
                  Marshal.FinalReleaseComObject(pPropStore)
              End If
          End Sub
      
      #End Region
      
      End Class
      

      【讨论】:

        【解决方案4】:

        更好和最简单的方法是在启动应用程序时更改 2 个注册表项,并在关闭应用程序时恢复它们?

        您只需在以下位置创建(如果不存在)EdgeUI 键:

        HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ImmersiveShell

        并添加新的 DWORD 键:DisableTLcorner & DisableCharmsHint

        禁用:

        DisableTLcorner = 1 DisableCharmsHint = 1

        对于启用更改为零或删除它们:

        DisableTLcorner = 0 DisableCharmsHint = 0

        所有这些都可以使用任何语言以编程方式轻松完成!!!

        【讨论】:

        • 太棒了!在我最初提出问题时,此信息不可用。我很高兴它比我想象的要简单得多!
        • 嗨,这绝对没有帮助,在这里。我手动和以编程方式添加了这个 reg 键,我仍然可以在 Windows 8.1 上拉动魅力栏并使用热角。然而奇怪的是:“ImmersiveShell”键没有任何价值,只有子键。这正常吗?
        【解决方案5】:

        简单的解决方案,并不完美,每次激活魅力栏时,您的应用程序都会停用,所以立即重新激活它,魅力栏就会消失。将此添加到您的 App.xaml.cs 中

         private enum WindowShowStyle : uint
            {  // find more info at http://stackoverflow.com/a/8210120/1245420
                Hide = 0, ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
                ShowNormalNoActvate = 4, Show = 5, Minimize = 6, ShowNoActivate = 8,
                Restore = 9, ShowDefault = 10, ForceMinimized = 11
            }
        
            [DllImport("user32.dll", SetLastError = true)]
            static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);
        
            [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
            static extern System.IntPtr FindWindowByCaption(System.IntPtr ZeroOnly, string lpWindowName);
        
            [DllImport("user32.dll")]
            static extern bool ShowWindow(System.IntPtr hWnd, WindowShowStyle nCmdShow);
        
            DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
            public App()
            {
                this.Deactivated += App_Deactivated;
                this.Activated += App_Activated;
                timer.Tick += delegate
                {
                    Application.Current.MainWindow.Activate();
                    System.IntPtr hWndCharmBar = FindWindowByCaption(System.IntPtr.Zero, "Charm Bar");
                                    ShowWindow(hWndCharmBar, 0);
                };
                timer.Interval = new TimeSpan(0, 0, 0, 0, 10);
            }
        
            void App_Activated(object sender, EventArgs e)
            {
                timer.Stop();
            }
        
            void App_Deactivated(object sender, EventArgs e)
            {
                timer.Start();
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-05
          • 1970-01-01
          • 2014-12-04
          • 1970-01-01
          • 2013-05-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多