【发布时间】:2020-04-07 06:36:30
【问题描述】:
我的应用程序的主窗口在任何时候都不应被允许获得焦点,因为它被另一个在使用它时不断需要焦点的应用程序调用。此外,我的应用程序始终是 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-Method 中,但这仅适用于 Debug。此外,当单击 Windows 任务栏中的应用程序时,它会重新获得焦点。我该怎么做才能消除窗口的焦点?有人有想法吗?
【问题讨论】: