tags:

views:

1153

answers:

10

I just want a c# application with a hidden main window that will process and respond to window messages.

I can create a form without showing it, and can then call Application.Run() without passing in a form, but how can I hook the created form into the message loop?

Is there another way to go about this?

Thanks in advance for any tips!

A: 

in the Form1 code file add this.Visible = false; to the constructor.

This will hide the window but it will flash for a sec before it is hidden. Alternatively you can write your own Application.Run command.

for more info http://social.msdn.microsoft.com/forums/en-US/winforms/thread/dece45c8-9076-497e-9414-8cd9b34f572f/

also you may want to set the this.ShowInTaskbar to false.

Sruly
A: 

You should look at creating a 'service' as this is an application without a form. See http://support.microsoft.com/kb/816169

Fraser
It may well be very difficult in recent versions of Windows to make a service which a message loop that responds in the same way as an app on the user's desktop.
Will Dean
I believe administrative permissions are needed in order to install a service however a standalone application can run just fine under a regular user account using the techniques discussed here.
jpierson
+1  A: 

Why can't you just pass the form when you call Application.Run? Given that it's clearly a blocking call, on what event do you want to show the form? Just calling form.Show() should be enough.

Noldorin
+4  A: 

Excellent! That link pointed me in the right direction. This seems to work:

        Form f = new Form1();
        f.FormBorderStyle = FormBorderStyle.FixedToolWindow;
        f.ShowInTaskbar = false;
        f.StartPosition = FormStartPosition.Manual;
        f.Location = new System.Drawing.Point(-2000, -2000);
        f.Size = new System.Drawing.Size(1, 1);
        Application.Run(f);

To keep it from showing up in Alt-Tab, you need it to be a tool window. Unfortunately, this prevents it from starting minimized. But setting the start position to Manual and positioning it offscreen does the trick!

Bear in mind that -2000,-2000 is rather close to the visible area of a some multi-monitor setups. You might want to go a bit further than that...
Will Dean
Or perhaps even use values from the Screen class to determine a point that will definitely be off screen.
jpierson
+3  A: 

You can create a class that inherits from System.Windows.Forms.NativeWindow (which provides basic message loop capability) and reference the Handle property in its constructor to create its handle and hook it into the message loop. Once you call Application.Run, you will be able to process messages from it.

Zach Johnson
+1  A: 

That sounds like the way Delphi does it by default. If you're a Delphi programmer trying to migrate/port something to C#, be prepared for a bunch of ugly hacks like the one you described in your answer. If not, why not try Delphi, in which you don't have to use ugly hacks like that? :P

Mason Wheeler
A: 

The best way is to use the following 1-2 lines in the constuctor:

this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false; // This is optional

You can even set the Minimized property in the VS Property window.

Tarion
+1  A: 
public partial class Form1 : Form
{
    private bool _isApplicationRun;

    public Form1(bool applicationRun)
    {
        InitializeComponent();
        _isApplicationRun = applicationRun;
    }

    protected override void SetVisibleCore(bool value)
    {
        if (_isApplicationRun)
        {
            _isApplicationRun = false;

            base.SetVisibleCore(false);
            return;
        }

        base.SetVisibleCore(value);
    }
}

static class Program
{

    [STAThread]
    static void Main()
    {

        Application.Run(new Form1(true));
    }
}
+1  A: 

I solved the problem like this:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Main main = new Main();
    Application.Run();
    //Application.Run(new Main());
}

This code resides in the Program.cs file, and you can see the original Application.Run method call commented out. I just create a Main class object (my main form class is named Main) and start application message loop w/o any parameters. This starts the application, initializes any form components but doesn't show the form.

Note: you have to have some method to get your window showing (like system tray icon, hotkey or timer or anything you might like).

kami
This is a nice, clean approach, but it might benefit from the addition of an ApplicationContext object so that you have control over when the application terminates.
Paul Keister
A: 

Using Kami's answer as an inspiration, I created a more complete concept. If you use this solution, don't ever show the hidden window. If you do, the user might close it and then you've lost the ability to control the application exit in an orderly way. This approach can be used to manage a Timer, NotifyIcon, or any other component that is happy living on an invisible form.

using System;
using System.Windows.Forms;

namespace SimpleHiddenWinform
{
    internal class HiddenForm : Form
    {
        private Timer _timer;
        private ApplicationContext _ctx;

        public HiddenForm(ApplicationContext ctx)
        {
            _ctx = ctx;
            _timer = new Timer()
            {
                Interval = 5000, //5 second delay
                Enabled = true
            };
            _timer.Tick += new EventHandler(_timer_Tick);
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            //tell the main message loop to quit
            _ctx.ExitThread();
        }
    }

    static class Program
    {
        [STAThread]
        static void Main()
        {
            var ctx = new ApplicationContext();
            var frmHidden = new HiddenForm(ctx);
            //pass the application context, not the form
            Application.Run(ctx);
        }
    }
}
Paul Keister