我正在开发一个wpf应用程序,而不是在用户关闭按钮时退出应用程序我将其最小化到托盘(类似于谷歌谈话).
void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}
Run Code Online (Sandbox Code Playgroud)
我需要的是,如果用户忘记了应用程序的实例并尝试打开新实例,我必须关闭第二个实例并将我的应用程序设置为前台应用程序.如果应用程序处于最小化状态(未隐藏),我可以执行此操作.我使用以下代码
protected override void OnStartup(StartupEventArgs e)
{
Process currentProcess = Process.GetCurrentProcess();
var runningProcess = (from process in Process.GetProcesses()
where
process.Id != currentProcess.Id &&
process.ProcessName.Equals(
currentProcess.ProcessName,
StringComparison.Ordinal)
select process).FirstOrDefault();
if (runningProcess != null)
{
Application.Current.Shutdown();
ShowWindow(runningProcess.MainWindowHandle, 5);
ShowWindow(runningProcess.MainWindowHandle, 3);
}
}
[DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
Run Code Online (Sandbox Code Playgroud)
当应用程序最小化时,它具有MainWindowHandle的一些唯一值.当我隐藏应用程序时,runningProcess的MainWindowHandle 显示为0.我认为这就是为什么我的应用程序在处于隐藏状态时不打开,但不知道如何修复它.
告诉我是否需要发布更多代码或澄清任何内容.先感谢您.
当我隐藏应用程序时,runningProcess的MainWindowHandle显示为0
你是对的.如果进程没有与之关联的图形界面(隐藏/最小化),则该MainWindowHandle值为零.
作为解决方法,您可以尝试HANDLE使用EnumDesktopWindows函数枚举所有打开的窗口来获取隐藏窗口,并将其进程ID与隐藏/最小化窗口的进程ID进行比较.
更新
WPF的WIN32窗口与标准WIN32窗口的行为略有不同.它的类名由单词HwndWrapper,创建它的AppDomain名称和唯一随机Guid(每次启动时更改)组成,例如,HwndWrapper [WpfApp.exe ;; 4d426cdc-31cf-4e4c-88c7-ede846ab6d44].
更新2
当使用该Hide()方法隐藏WPF的窗口时,它会在内部调用UpdateVisibilityProperty(Visibility.Hidden),然后将内部可见性标志设置UIElement为false.当我们调用Show()方法时WPF Window,UpdateVisibilityProperty(Visibility.Visible)调用,并UIElement切换内部可见性标志.
当我们使用the显示WPF窗口时ShowWindow(),该UpdateVisibilityProperty()方法不会被触发,因此内部可见性标志不会被反转(这会导致窗口以黑色背景显示).
通过查看WPF Window内部实现,在不调用Show()or Hide()方法的情况下切换内部visiblity标志的唯一方法是发送WM_SHOWWINDOW消息.
const int GWL_EXSTYLE = (-20);
const uint WS_EX_APPWINDOW = 0x40000;
const uint WM_SHOWWINDOW = 0x0018;
const int SW_PARENTOPENING = 3;
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc ewp, int lParam);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("user32.dll")]
private static extern uint GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern uint GetWindowText(IntPtr hWnd, StringBuilder lpString, uint nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern bool GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
static bool IsApplicationWindow(IntPtr hWnd) {
return (GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_APPWINDOW) != 0;
}
static IntPtr GetWindowHandle(int pid, string title) {
var result = IntPtr.Zero;
EnumWindowsProc enumerateHandle = delegate(IntPtr hWnd, int lParam)
{
int id;
GetWindowThreadProcessId(hWnd, out id);
if (pid == id) {
var clsName = new StringBuilder(256);
var hasClass = GetClassName(hWnd, clsName, 256);
if (hasClass) {
var maxLength = (int)GetWindowTextLength(hWnd);
var builder = new StringBuilder(maxLength + 1);
GetWindowText(hWnd, builder, (uint)builder.Capacity);
var text = builder.ToString();
var className = clsName.ToString();
// There could be multiple handle associated with our pid,
// so we return the first handle that satisfy:
// 1) the handle title/ caption matches our window title,
// 2) the window class name starts with HwndWrapper (WPF specific)
// 3) the window has WS_EX_APPWINDOW style
if (title == text && className.StartsWith("HwndWrapper") && IsApplicationWindow(hWnd))
{
result = hWnd;
return false;
}
}
}
return true;
};
EnumDesktopWindows(IntPtr.Zero, enumerateHandle, 0);
return result;
}
Run Code Online (Sandbox Code Playgroud)
用法示例
...
if (runningProcess.MainWindowHandle == IntPtr.Zero) {
var handle = GetWindowHandle(runningProcess.Id, runningProcess.MainWindowTitle);
if (handle != IntPtr.Zero) {
// show window
ShowWindow(handle, 5);
// send WM_SHOWWINDOW message to toggle the visibility flag
SendMessage(handle, WM_SHOWWINDOW, IntPtr.Zero, new IntPtr(SW_PARENTOPENING));
}
}
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3605 次 |
| 最近记录: |