前段时间写的C#程序启动欢迎窗体实现,在运行时虽然能显示欢迎窗体,但运行后不能把主窗体提到最前。结合网上搜罗了好多资料,自己做了好几个方案来实现,最终可以解决了。
起因:
2000/XP 改变了SetForegroundWindow的执行方式,不允许随便把窗口提前,打扰用户的工作。
思路:
可以用附加本线程到最前面窗口的线程,从而欺骗windows。
实现:
原理:将显示欢迎窗体的线程作为Foreground的线程。
1. API函数的导入
public const int SW_HIDE = 0;
public const int SW_NORMAL = 1;
public const int SW_SHOWMINIMIZED = 2;
public const int SW_SHOWMAXIMIZED = 3;
[DllImport(“User32.dll”)]
public static extern void SetForegroundWindow(IntPtr hwnd);
[DllImport(“User32.dll”)]
public static extern IntPtr GetForegroundWindow();
[DllImport(“User32.dll”)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, IntPtr pProcId);
[DllImport(“User32.dll”)]
public static extern bool AttachThreadInput(int idAttach, int idAttachTo, int fAttach);
[DllImport(“User32.dll”)]
public static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
2. 使用API函数实现
private static void ActivateMainInstance(IntPtr mainWindowHandle, int foreId)
{
int curId = GetWindowThreadProcessId(mainWindowHandle, IntPtr.Zero);
if (curId != foreId)
{
AttachThreadInput(foreId, curId, 1);
SetForegroundWindow(mainWindowHandle);
AttachThreadInput(foreId, curId, 0);
}
else
{
SetForegroundWindow(mainWindowHandle);
}
ShowWindowAsync(mainWindowHandle, SW_SHOWMAXIMIZED);
}
3. 调用:
private static ApplicationContext _context = null;
private static SplashScreen _splash = null;
private static MainFrame _mForm = null;
private static void OnAppIdle(object sender, EventArgs e)
{
if (_context.MainForm == null)
{
Application.Idle -= new EventHandler(OnAppIdle);
// Initialize main frame and show
_mForm.InitializeFrame(); // 花时间点
_context.MainForm = _mForm;
_context.MainForm.Show();
// Active main form
ActivateMainInstance(_mForm.Handle, _splash.ThreadId);
// Close splash screen
_splash.Close();
_splash = null;
}
}
4. Main函数中:
// Show splash screen
_splash = new SplashScreen();
_splash.Run();
// Application running
_mForm = new MainFrame();
_context = new ApplicationContext();
Application.Idle += new EventHandler(OnAppIdle);
Application.Run(_context);
5. SplashScreen的实现:
public class SplashScreen
{
private SplashForm _sForm = null;
private Thread _workThread = null;
///
///
private void Show()
{
_sForm = new SplashForm();
_sForm.ShowDialog();
}
///
///
public int ThreadId
{
get
{
return _workThread.ManagedThreadId;
}
}
///
///
public void Run()
{
_workThread = new Thread(new ThreadStart(Show));
_workThread.Start();
}
///
///
public void Close()
{
if (_sForm != null)
{
_sForm.HideSplash = true;
_workThread.Join();
_workThread = null;
}
}
}
🙂
C#.net设置窗体属性
theForm.TopMost=true;
可以达到相同的效果。
回复王伟晔:
你说的这个我知道,但结果是这个窗体总在之前已打开程序的窗体前面,这是不合理的。合理的应该是把刚刚运行的窗体提到前面,但不影响切换到别的程序时显示其窗体。