Основному окну моего приложения нельзя позволять получать фокус в любое время, так как оно вызывается другим приложением, которое постоянно нуждается в фокусе при работе с ним. Кроме того, мое приложение всегда TopMost, разрешено запускать только с одним экземпляром и при вызове будет обрабатывать аргументы командной строки для запуска в другом контексте. Эта часть уже обработана и работает хорошо.
Я не могу добиться, по какой-то причине не получая фокусировки. Я несколько часов пытался использовать разные решения - все не работает так, как я ожидаю. Прежде всего, вот соответствующий XAML главного окна:
<mah:MetroWindow x:Class="Sprachrekorder.Code.View.Gui"
x:Name="G"
...
mc:Ignorable="d"
ResizeMode="NoResize"
WindowStartupLocation="Manual"
ShowTitleBar="true"
Topmost="True"
ShowActivated="False" <- ONLY WORKS WHEN INITIALLY RUNNING THE PROGRAM, BUT FAILS WHEN CALLING THE SAME (ALREADY RUNNING) INSTANCE AGAIN
Focusable="False" <- HAS NO IMPACT
SourceInitialized="Gui_OnSourceInitialized"
d:DataContext="{d:DesignInstance {x:Type viewModel:MainViewModel}, IsDesignTimeCreatable=False}"
ShowCloseButton="False"
cust:WindowPosition.IsLocked="{Binding Settings.ActualConfig.WindowFixed, UpdateSourceTrigger=PropertyChanged}">
Код основного окна позади:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
//private static IntPtr GetWindowLongPtr ( IntPtr hWnd, int index ) <- USING THIS CODE ALSO HAS NO IMPACT
//{
// return (IntPtr.Size == 4) ? GetWindowLongPtrA(hWnd, index) : GetWindowLongPtrW(hWnd, index);
//}
//private static IntPtr SetWindowLongPtr ( IntPtr hWnd, int index, IntPtr newValue )
//{
// return (IntPtr.Size == 4) ? SetWindowLongPtrA(hWnd, index, newValue) : SetWindowLongPtrW(hWnd, index, newValue);
//}
//[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)]
//private static extern IntPtr GetWindowLongPtrW ( IntPtr hWnd, int nIndex );
//[DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)]
//private static extern IntPtr GetWindowLongPtrA ( IntPtr hWnd, int nIndex );
//[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
//private static extern IntPtr SetWindowLongPtrW ( IntPtr hWnd, int nIndex, IntPtr dwNewLong );
//[DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]
//private static extern IntPtr SetWindowLongPtrA ( IntPtr hWnd, int nIndex, IntPtr dwNewLong );
public Gui()
{
Main = new MainViewModel();
DataContext = Main;
InitializeComponent();
Main.Init();
Loaded += (s, e) =>
{
WindowHandle = new WindowInteropHelper(Application.Current.MainWindow ?? throw new InvalidOperationException()).Handle;
HwndSource.FromHwnd(WindowHandle)?.AddHook(HandleMessages);
//Set the window style to noactivate. <- DOES NOT WORK
var currentValue = GetWindowLongPtr(WindowHandle, GWL_EXSTYLE);
var newValue = new IntPtr(currentValue.ToInt64() | WS_EX_NOACTIVATE);
SetWindowLongPtr(WindowHandle, GWL_EXSTYLE, newValue);
};
}
private static IntPtr HandleMessages(IntPtr handle, int message, IntPtr wParameter, IntPtr lParameter, ref Boolean handled)
{
//Deactivate Window focus completely <- ONLY SEEMS TO WORK IN DEBUG
if (message == WM_MOUSEACTIVATE)
{
handled = true;
return new IntPtr(MA_NOACTIVATE);
}
if (handle != WindowHandle) return IntPtr.Zero;
var data = UnsafeNative.GetMessage(message, lParameter); <- THIS PART HANDLES THE COMMAND LINE ARGS IF APPLICATION IS ALREADY RUNNING AND IS CALLED AGAIN
if (data == null || Application.Current.MainWindow == null) return IntPtr.Zero;
if (Application.Current.MainWindow.WindowState == WindowState.Minimized) Application.Current.MainWindow.WindowState = WindowState.Normal;
UnsafeNative.SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);
var args = data.Split(' ');
HandleParameter(args);
handled = true;
return IntPtr.Zero;
}
private void Gui_OnSourceInitialized(object sender, EventArgs e)
{
var interopHelper = new WindowInteropHelper(this); // <- THIS CODE PART HAS NO IMPACT
int exStyle = GetWindowLong(interopHelper.Handle, GWL_EXSTYLE);
SetWindowLong(interopHelper.Handle, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
}
Части класса UnsafeNative:
public const int WM_COPYDATA = 0x004A;
public static string GetMessage(int message, IntPtr lParam)
{
if (message != WM_COPYDATA) return null;
try
{
var data = Marshal.PtrToStructure<COPYDATASTRUCT>(lParam);
var result = string.Copy(data.lpData);
return result;
}
catch
{
return null;
}
}
Я прокомментировал соответствующие части в моем коде. Кажется, что наиболее эффективная часть -
if (message == WM_MOUSEACTIVATE)
{
handled = true;
return new IntPtr(MA_NOACTIVATE);
}
в методе HandleMessages основного класса, но это работает только в Debug. Также при нажатии на приложение на панели задач windows оно восстанавливает фокус. Что я могу сделать, чтобы убрать фокус окна? У кого-нибудь есть идея?