在激活最小化的非模式形式时,是否有人在使用USER32函数在Citrix中运行C#Winforms应用程序时遇到问题?
我试图做的是在非模式形式的Activate事件中,检查是否有可用的模式形式,如果有,将其带到前台并激活它。
由于我们的应用程序存在系统限制,因此我无法使用Application.OpenForms来检测可用的表单类型(或使用任何表单属性来激活窗口状态或将窗口状态设置为表单),因此我使用的是User32方法GetWindow和SetActiveWindow(或SetForegroundWindow),并使用Application的MainWindowHandle值确定Modal窗体的句柄,将其置于前台并激活。
代码如下:
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms.VisualStyles;
namespace WindowsFormsApp
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr GetWindow(IntPtr hWnd, UInt32 wCmd);
[DllImport("user32.dll")]
static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, UInt32 uFlags);
[DllImport("user32.dll")]
static extern Boolean ShowWindow(IntPtr hWnd, UInt32 wCmd);
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr GetActiveWindow();
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
var nonModalButton = new Button() { Text = "Open non-modal window", Width = 200, Height = 30, Top = 10, Left = 10 };
var modalButton = new Button() { Text = "Open modal window", Width = 200, Height = 30, Top = 50, Left = 10 };
UInt32 GW_ENABLEDPOPUP = 6;
// click event for modalButton
modalButton.Click += (s, e) =>
{
var modalWindow = new Form() { Text = "Modal Window"};
var newModalWindowButton = new Button() { Text = "Open child modal window", Width = 200, Height = 30, Top = 50, Left = 10 };
// add click event to newModalWindowButton to show as a modal
newModalWindowButton.Click += (s1, e1) => { (new Form() { Text = "Child Modal Window" }).ShowDialog(); };
// add to list of controls for modalWindow Form
modalWindow.Controls.Add(newModalWindowButton);
// open new ModalWindow as a modal form
modalWindow.ShowDialog((IWin32Window)s);
//modalWindow.ShowDialog();
};
// click event for non-modalButton
nonModalButton.Click += (s, e) =>
{
var nonModalWindow = new Form() { Text = "Non-Modal Window" };
var newModalWindowButton = new Button() { Text = "Test", Width = 200, Height = 30, Top = 50, Left = 10 };
nonModalWindow.Controls.Add(newModalWindowButton);
// when non-modalWindow form is activated, find any active modal windows and activate the last one in the form collection
nonModalWindow.Activated += (sender, ev) =>
{
Form nonModalForm = sender as Form;
if (!nonModalForm.CanFocus)
{
var mainWindowHandlePtr = Process.GetCurrentProcess().MainWindowHandle;
var modalPopupPtr = GetWindow(mainWindowHandlePtr, GW_ENABLEDPOPUP);
var NewPtr = SetActiveWindow(modalPopupPtr);
if (NewPtr == IntPtr.Zero)
{
SetForegroundWindow(modalPopupPtr);
}
}
};
nonModalWindow.Show((IWin32Window)s);
};
this.Controls.AddRange(new Control[] { modalButton, nonModalButton });
this.Show();
}
#endregion
}
}
如果我以exe身份运行此文件,请按照以下步骤在citrix的范围之外:
1)通过单击“打开非模态窗口”按钮来打开非模态表单
2)最小化非模态形式
3)通过单击“打开模态窗口”按钮来打开模态表单
4)通过点击工具栏中的图标来激活非模式表单
上面的代码会将模态形式带到前台,而非模态形式将在它后面。我还注意到newPtr值(SetActiveWindow的结果)是NonModalForm的句柄。
如果我使用相同的步骤在citrix中运行此exe,则非模式形式仍保留在前台,并且newPtr的值为0。
如果未将非模态形式最小化,而我尝试将其激活,则会将模态形式带到前台。
使这些步骤在Citrix中起作用的更好(推荐)方法吗?非常感谢您的任何建议。