我有一个通过Visual Studio安装项目部署的应用程序,但是,我必须创建一些自定义Windows窗体来从用户收集一些特定数据。在安装项目(I.E.MSI)部署应用程序文件之后,这些表单显示在应用程序的Installer类的Install()方法中。问题是当我的表单出现时,它们出现在Setup Project的窗口下,而不是屏幕上最顶层的表单。然后,如果用户甚至注意到,则必须通过单击任务栏中的图标来手动关注表单以将其启动。
答案 0 :(得分:4)
我所要做的就是从进程列表中选择Setup项目的窗口,并在我显示它们时将其设置为自定义表单的所有者。以下是我使用的步骤的细分:
我自己,我创建了一个方法,将Setup Project的窗口作为WindowWrapper返回,然后在每个Installer类的方法(安装,提交,卸载和回滚)中使用它来设置每个表单和消息框的所有者我是创建
此外,不要更改自定义表单的任何子表单或消息框的所有者(除了“this”之外),因为它们将由显示它们的自定义表单所有;否则它们将显示在安装项目的窗口上但在自定义表单下,而不是我们想要的。
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;
}
答案 1 :(得分:1)
选择列表的第一个元素并不是一个好习惯,下面的代码经过测试和工作。
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;
}
答案 2 :(得分:0)
使用以下代码。此代码专注于您的表单
[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();
}
答案 3 :(得分:0)
MSDN解释了如何将表单放在前面并将其保留在前面。