У меня есть Surface Pro, который мне нужно «заблокировать» в качестве режима киоска. Я знаю, что для «Режима киоска» идет обновление … однако мне нужно сделать это до этого.
Я искал по всему Интернету, но кажется, что вы не можете отключить панель Charm от удара по экран. Я нашел способы отключения трекпада … но, к сожалению, поскольку этот планшет будет использоваться без клавиатуры, мне нужно отключить панель Charm.
Моя новая мысль состоит в том, чтобы переместить всю панель Charm HWND на тысячи пикселей за пределы экрана или, возможно, установить для нее стиль окон, чтобы она не появлялась. Я пытался использовать Spy ++ и пользовательский EnumWindows
на основе консольного приложения, чтобы дать мне несколько оконных дескрипторов … однако я не могу держать панель Charm открытой достаточно долго, чтобы они вступили в силу.
Итак, мой вопрос: как я могу найти дескриптор окна (HWND
) для Charm Bar в Windows 8? Или, как я могу получить ссылку на панель Charm другим способом, чтобы бросить SetWindowLong
или же SetWindowPos
на него?
На самом деле, я нашел способ сделать это (по-видимому, никто другой не имеет: /).
Для тех, кто интересуется, такие кнопки как «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. Заголовок окна для этого оказывается, 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
есть, чтобы остановить поток, разбивающий ЦП — но задержка также позволяет Charm Bar появляться в течение доли секунды. Мне еще предстоит открыть панель чудо-кнопок и нажать кнопку достаточно быстро, прежде чем нить снова ее скрывает, так что это нормально. Понижение времени сна, очевидно, делает это быстрее.
Другая проблема с Windows 8 заключается в том, что если у вас есть какой-то слайдер (в моем приложении у меня есть ListBox
содержит изображения для галереи) тогда вы можете фактически скользить в сторону экрана … держать палец там, и получить доступ к панели задач …
Итак … следующая часть закрывает панель задач:
IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
ShowWindow(hWndTray, 0);
..затем я показываю это снова в приложении закрыть:
IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
ShowWindow(hWndTray, 1);
Функционально это все, что мне нужно для моего приложения. Надеюсь, что это помогает кому-то.
Также хотелось бы отметить, что часы содержатся в окне с надписью «Часы и дата».
IntPtr hWndCharmClock = FindWindowByCaption(IntPtr.Zero, "Clock and Date");
Я сделал небольшое приложение для переключения панели чудо-кнопок: https://bitbucket.org/darkwingduck/charmsbartoggle/overview
Вот как можно отключить панель чудо-кнопок, когда приложение развернуто с помощью взаимодействия 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
Лучше и проще всего изменить 2 ключа реестра при запуске приложения и восстановить их обратно при закрытии?
Все, что вам нужно, это создать (если не существовало) EdgeUI ключ под:
HKEY_CURRENT_USER \ Software \ Microsoft \ Windows \ CurrentVersion \ ImmersiveShell
и добавьте новые ключи DWORD: DisableTLcorner & DisableCharmsHint
Для отключения:
DisableTLcorner = 1 DisableCharmsHint = 1
Для включения измените на ноль или удалите их:
DisableTLcorner = 0 DisableCharmsHint = 0
Все это можно легко сделать программно, используя любой язык !!!!
Простое решение, не идеальное, каждый раз, когда активируется панель чудо-кнопок, ваше приложение деактивируется, поэтому активируйте его немедленно, и панель чудо-кнопок исчезнет. добавьте это в ваш 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();
}