Question

Since Compact Framework calls Show() on the form passed to Application.Run(), I decided to create my own message pump.

I've no idea how can I do that.

Any help (like a simple example) will be appreciated.

Was it helpful?

Solution

  • Did you try to catching the VisibleChanged event?

this.Shown += new EventHandler(Form1_Shown);

void Form1_Shown(object sender, EventArgs e)
{
    this.Hide();
}
  • You can also try to intercept the message by overriding the WndProc.
    protected override void WndProc(ref Message m)
    {
        const int SW_SHOW = 5;
        if (m.Msg == SW_SHOW)
        {
            //DoSomething();
        }

        base.WndProc(ref m);
    }
  • A typical message pump looks like following:
MSG msg;
while(GetMessage(&msg, hwnd, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    // DoSomething.
}

OTHER TIPS

I found this to be a larger problem than you would anticipate for a windows form application. For my solution I pulled suggestions from three different website and found this solution to work very well. For my needs I have a Windows Service that has a UI controller component in the system tray. The UI needs to start up minimized with just the tray icon and a context menu for the icon. The UI operates as a modal dialog when activated, allowing the user to start a long running process on a background thread, once started the UI needs to resume taking responses from the user.

In the constructor for the Windows Form class I set the ControlBox on and disabled the minimize and maximize buttons:

public SystemTrayApp()
{
    InitializeComponent();
    this.Visible = false;
    // Hide Maximize and Minimize buttons on form
    this.StartPosition = FormStartPosition.CenterScreen;
    this.MaximizeBox = false;
    this.MinimizeBox = false;
}

The ControlBox needs to be enable to allow the user to move the dialog around on the screen but not change it size, to disable the form close button, red X in upper right hand corner of form, I used:

// Force form close button to be disabled
private const int CP_NOCLOSE_BUTTON = 0x200;
protected override CreateParams CreateParams 
{
   get 
   {
      CreateParams cp = base.CreateParams;
      cp.ClassStyle = cp.ClassStyle | CP_NOCLOSE_BUTTON;
      return cp;
   }
}

In the main program where the static Main method runs on application start-up, I changed the default Application.Run to:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        SystemTrayApp systemTrayApp = new SystemTrayApp();
        systemTrayApp.Text = "File Copy Service Controller";

        // Show the instance of the form modally.
        systemTrayApp.ShowInTaskbar = true;
        systemTrayApp.ShowDialog();
        Application.Run();
    }
 }

Now show the design page for the Windows form, right click the form and select properties, next select the events button to show all events for the form. Scroll down to the Shown event and double click, a new event handler will be added to your source code. Navigate to the method and add this.Hide() to the handler:

// Runs the first time the application starts
private void SystemTrayApp_Shown(object sender, EventArgs e)
{
   this.Hide();
}

Finally open the properties page for the Windows Form project and select the Application tab. Under Startup object, select the Program class as the startup object.

You will need to add a button or menu control to your dialog to allow closing the form without terminating the application, set the button or menu control to hide the application, leaving it running in the system tray.

Replacing the message loop in the Application class is not practical. There is far more going on then the boilerplate Windows message loop. It isn't the real problem anyway, the Application class forces the form to become visible with a call to ShowWindow(). That's necessary because forms are lazily initialized, without the ShowWindow() call it never creates the native Window handle.

This issue is easy to fix in the regular .NET framework version by overriding SetVisibleCore():

protected override void SetVisibleCore(bool value) {
  if (!this.IsHandleCreated) {
    this.CreateHandle();
    value = false;  // Prevent becoming visible the first time
  }
  base.SetVisibleCore(value);
}

But I don't think that's available in CF. To find a solution, you'll need to explain exactly why you want to prevent the UI from being shown. Without any created window handle, an app is usually dead as a doornail. It could be as simple as delaying the Application.Run() call.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow