[英]how to bring custom window form on top of setup project window?
我有一個正在通過 Visual Studio 安裝項目部署的應用程序,但是,我必須創建一些自定義 Windows Forms 來從用戶那里收集一些特定數據。 這些 forms 顯示在應用程序安裝程序 class 的 Install() 方法中,就在安裝項目(即 MSI)部署應用程序文件之后。 問題是,當我的 forms 出現時,它們出現在安裝項目的 window 下面,而不是屏幕上最頂層的窗體。 如果用戶甚至注意到它,則必須通過單擊任務欄中的圖標來手動聚焦該表單以將其調出。
我所要做的就是從進程列表中選擇安裝項目的 window,並將其設置為我正在顯示的自定義 forms 的所有者。 以下是我使用的步驟的細分:
我自己創建了一個方法,將安裝項目的 window 作為 WindowWrapper 返回,然后在每個 Installer 類的方法(安裝、提交、卸載和回滾)中使用它來設置我正在創建的每個表單和消息框的所有者。
另外,不要更改任何子 forms 的所有者或自定義 forms 的消息框(除了“this”),因為它們將由顯示它們的自定義 forms 擁有; 否則它們將顯示在安裝項目的 window 之上,但在自定義 forms 之下,這不是我們想要的。
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
ExecuteSqlScript();
}
catch (Exception ex)
{
throw ex;
}
}
private void ExecuteSqlScript()
{
IntPtr hwnd = IntPtr.Zero;
WindowWrapper wrapper = null;
Process[] procs = Process.GetProcessesByName("msiexec");
if (null != procs && procs.Length > 0)
hwnd = procs[0].MainWindowHandle;
wrapper = new WindowWrapper(hwnd);
//Set the windows forms owner to setup project so it can be focused and
//set infront
frmInstance objInstance = new frmInstance();
if (null != wrapper)
objInstance.ShowDialog(wrapper);
else
objInstance.ShowDialog();
}
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
選擇列表的第一個元素不是好的做法,下面的代碼已經過測試並且可以正常工作。
internal static IntPtr InstallerWindow()
{
IntPtr hwnd = IntPtr.Zero;
foreach (var proc in Process.GetProcessesByName("msiexec"))
{
if (proc.MainWindowHandle == IntPtr.Zero)
continue;
if (string.IsNullOrEmpty(proc.MainWindowTitle))
continue;
hwnd = proc.MainWindowHandle;
break;
}
return hwnd;
}
使用以下代碼。 此代碼專注於您的表單
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
/// <summary>The GetForegroundWindow function returns a handle to the foreground window.</summary>
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(HandleRef hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
myform.Show();
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const uint SW_SHOW = 5;
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(myform.Handle);
ShowWindow(objFrmViewer.Handle, SW_SHOW);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(myform.Handle);
ShowWindow(myform.Handle, SW_SHOW);
}
myform.Activate();
}
MSDN 解釋了如何將表單置於最前面並將其保持在最前面。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.