Reputation: 19242
I have an application that is being deployed via a Visual Studio Setup Project, however, I had to create some custom Windows Forms to collect some specific data from the user. These forms are shown in the Install() method of the application's Installer class, right after application files have been deployed by the Setup Project (I.E. the MSI). The problem is that when my forms appear, they appear under the Setup Project's window rather than being the topmost form on the screen. The form then has to be focused on manually by clicking on its icon in the taskbar to bring it up, if the user even notices it.
Upvotes: 2
Views: 4397
Reputation: 19242
All I had to do was pick the Setup project’s window from the list of processes and set it as the owner of the custom forms as I was displaying them. Here’s a breakdown of the steps I used:
Myself, I made a method which returns the Setup Project’s window as a WindowWrapper, and then used that in each of the Installer class’s methods (Install, Commit, Uninstall and Rollback) to set the owner of every form and messagebox I am creating.
Also, don’t change the owners of any child forms or messageboxes of your custom forms (except maybe to “this”), as they’ll be owned by the custom forms that show them; otherwise they’ll show up over the Setup project’s window but under the custom forms, not that we desired.
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;
}
Upvotes: 4
Reputation: 149
picking the first element of your list is not good practice, code below is tested and working.
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;
}
Upvotes: 1
Reputation: 138
MSDN explains how to bring a form to the front and keep it at the front.
http://msdn.microsoft.com/en-us/library/3saxwsad.aspx
Upvotes: 0
Reputation: 157
Use the following code . This code make focus on your form
[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();
}
Upvotes: 0