从隐藏的控制台应用程序显示表单

本文关键字:显示 表单 应用程序 控制台 隐藏 | 更新日期: 2023-09-27 17:52:16

我有一个运行控制台应用程序的主应用程序。控制台应用程序通常是隐藏启动的(ProcessWindowStyle.Hidden),但出于测试目的,我可以在显示的窗口中运行它。

在控制台应用程序中,我可以加载和执行插件。其中一个插件试图打开一个WinForm对话框。如果控制台应用程序是可见的,它可以正常工作,但如果控制台是隐藏的,它就不再工作了。

I have try:

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form());

和我也尝试了同样的在一个新的线程

Thread t = new System.Threading.Thread(start);
t.Start();
t.Join();

,其中start()包含前面的东西。另外我试了ShowDialog()

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var f = new Form();
f.ShowDialog();

所有方法都没有显示窗口。

在WinDbg中,本机调用堆栈总是包含NtUserWaitMessage():

0:000> k
ChildEBP RetAddr  
0038dd58 7b0d8e08 USER32!NtUserWaitMessage+0x15

和托管调用堆栈总是包括WaitMessage(), FPushMessageLoop()RunMessageLoop():

0:000> !clrstack
OS Thread Id: 0x47c4 (0)
ESP       EIP     
0045e560 76bff5be [InlinedCallFrame: 0045e560] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()
0045e55c 7b0d8e08 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
0045e5f8 7b0d88f7 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
0045e64c 7b0d8741 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
0045e67c 7b5ee597 System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form)
0045e690 7b622d98 System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)
0045e71c 7b622faf System.Windows.Forms.Form.ShowDialog()

如何从隐藏的控制台窗口显示WinForms表单?

SSCCE:

将此编译为Windows窗体应用程序:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        var startInfo = new ProcessStartInfo("Console.exe");
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        Process.Start(startInfo);
    }
}

将其编译为控制台应用程序:

class Program
{
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        var mainForm = new Form();
        // Enable next line to make it show
        // mainForm.Visible = true;
        Application.Run(mainForm);
    }
}

从隐藏的控制台应用程序显示表单

使用Winspector Spy我发现窗口实际上是可用的,但它没有WS_VISIBLE样式。将该样式应用到窗体上,使其可见,并显示在Windows任务栏中。

解决方案是在显示表单之前使其可见,因此下面的操作有效:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var f = new Form()
f.Visible = true;
Application.Run(f);

因为在我的情况下,我想获得返回值,我应该调用ShowDialog()。但是,在已经可见的表单上调用ShowDialog()是不允许的,所以我坚持使用Application.Run(f)并自己检索结果:

var answer = configForm.DialogResult;