Start a hidden, single instance, animated window?

cjard

Well-known member
Joined
Apr 25, 2006
Messages
7,081
Programming Experience
10+
I'm trying to make an app that will start up hidden. There are some complications around it but i've gotten to the stage where i do this:


Set windowstate = minimized
Set showintaskbar = false


The app starts minimized no button - it doesnt appear on screen
The Shown event handler fires, where i:

VB.NET:
If Me.Visible AndAlso Me.WindowState == Minimized Then
  Me.Visible = False
  Me.WindowState = Normal
End If

The form is turned invisible then restored. At no point does it appear on screen but the issue I have... is that if I Show() it, it does not appear.

The show has been attachd to the notifyicon doubleclick - if I break on that and examine my form I find that even though i've already set the windowstate to normal, it has reverted to minimized and the Location, is set to -32000, -32000 ; very far off screen.

If I reset it to Normal, and set location to centre screen, then call show, a very small box appears in the centre. The form has again reverted to minimized.


Does anyone know why this happens? I'm struggling to un-minimize this form and I cant understand why
 
Last edited:
you should just post the project so we can see where the code is being used in relation to the rest of the code that's creating the problem
 
I haven't tried this, but why minimize it at all? It strikes me that if it's visible property is set to false then setting it to minimized doens't really accomplish anything here. If you are using the animatewindow api with the flags set to AW_HIDE OR AW_BLEND to hide it then thats gonna be good enough. Then to show combine AW_BLEND OR AW_ACTIVATE. I've had a long day so sorry if i've missed something here:)
 
you should just post the project so we can see where the code is being used in relation to the rest of the code that's creating the problem

can you read c#?


I haven't tried this, but why minimize it at all? It strikes me that if it's visible property is set to false then setting it to minimized doens't really accomplish anything here. If you are using the animatewindow api with the flags set to AW_HIDE OR AW_BLEND to hide it then thats gonna be good enough. Then to show combine AW_BLEND OR AW_ACTIVATE. I've had a long day so sorry if i've missed something here:)

Sorry.. I maybe havent given a complete picture.

I have to set it to minimized because I do not know how to prevent it from showing - I dont call Show() on it, the framework does, first time the application starts up..

The general way a .NET app starts is that a new instance of the main form is created and passed to the Application.Run() method whereby a message processing loop is set up and the form is shown automatically.

In a singleinstance application, a mutex is setup and locked. The pplication may also start a remoting server if it chooses so that subsequent instances can communicate command line parameters they were started with before they quit. The Visual Basic team at microsoft did a lot of this hard work and put it in Microsoft.VisualBasic.dll so that all a VB user has to do is tick the "Single Instance Application" in the properties screen and then write code for the event that fires when another instance is launched.

So far, so good.

Instead of Application.Run, a subclass of it is used in Single Instance scenarios, and this subclass is also subject to the restriction that it calls Show() on the main form. I'm using a wrapper for the AnimateWindow API, written by jmcilhinney that, upon form show, will animate the showing of the window with an alpha blend. As a result, I cannot hide my main window by setting its opacity to 0 - upon running the app, ApplicationChild.Run() will call show which causes the wrapper to activate and the API call will cause it to become 100% opaque.

The way to make an app start hidden is to set it minimized, so that even if it is shown, it does not appear on screen. To avoid it showing in the taskbar, ShowInTaskBar is set to false also. After the first showing, the Shown event is fired. Whatever state our form was in before, it is now visible, so we hide it again and restore it. The hidden window is restored to normal zoom state and can then be shown properly by e.g. a doubleclick on a tray icon.

I cannot figure out why my form has a propensity to re-minimized itself to -32000, -32000. Even if I halt the program, move it to centre screen and double click it to restore, it briefly flashes maximized before minimizing again and disappearing back to -32000, -32000
 
I must admit that i'm having trouble envisaging this. It probably would be better to see the project. C# isn't my strongest language but i have no problems with VC++ so it shouldn't take long to work through it. At a guess i'm gonna say that is has to do with the way that the AnimateWindow API shows the window. If you were to call the ShowWindow API or SetWindowPos you may find it will work.
 
OK :)

It's not rocket scient and i'll comment the code with VB style comments:



VB.NET:
  [COLOR="green"]'all C# programs are started via a "Sub Main" in a "Module" (static class)
  [/COLOR]static class Program
  {
    [COLOR="green"]'this is the single instance of the main form, called MainForm
   [/COLOR] static MainForm mf;

[COLOR="green"]    'equivalent of Sub Main. args is a string array of the command line arguments[/COLOR]
    static void Main(string[] args)
    {

      [COLOR="green"]'declare a boolean to indicate whether 1 arg of "/background" was passed
      [/COLOR]bool backgroundMode = (args != null && args.Length == 1 && args[0].Equals("/background"));
      
      [COLOR="green"]'instance of the main form - most of the interesting stuff is set in the designer[/COLOR]
      mf = new MainForm();
      
 [COLOR="green"]     'instance of jmc's wrapper - attaches to form and auto play anim when form shown or hidden[/COLOR]
      FormAnimation.FormAnimator fa = new FormAnimation.FormAnimator(mf, FormAnimation.FormAnimator.AnimationMethod.Blend, 250);

 [COLOR="green"]     'instance of the class below, provided by the Microsoft.VisualBasic dll for single instancing an app[/COLOR]
      SingleInstanceApplication.Run(mf, StartupNextInstanceHandler, backgroundMode);
    }

    [COLOR="green"]'every time the app is started when it is already running, this event occurs
    [/COLOR]static void StartupNextInstanceHandler(object sender, StartupNextInstanceEventArgs e)
    {
    [COLOR="green"]  'when event handler finishes the app should be brought to front. moot in my case
      'because  MainForm.TopMost = true[/COLOR]
      e.BringToForeground = true;
      [COLOR="Green"]'if the app is currently hidden, show it[/COLOR]
      if(!mf.Visible)
        mf.Show();
      else
        mf.BringToFront();
    }
  }

  [COLOR="green"]'our customising of the WFAB 
 [/COLOR] public class SingleInstanceApplication :WindowsFormsApplicationBase
  {
 [COLOR="green"]   'these properties are typical of most apps, and we set it single instance here too[/COLOR]
    private SingleInstanceApplication()
    {
      base.IsSingleInstance = true;
      base.ShutdownStyle = ShutdownMode.AfterMainFormCloses;
      base.EnableVisualStyles = true;
    }
[COLOR="green"]
    'this is the method that sets up the messaging loop and runs the app[/COLOR]
    public static void Run(Form f, StartupNextInstanceEventHandler startupHandler, bool startHidden)
    {
      SingleInstanceApplication app = new SingleInstanceApplication();
      app.StartupNextInstance += startupHandler;

      [COLOR="green"]'minimize the app now - its ShowInTaskBar false so it looks hidden
      [/COLOR]if(startHidden)
        f.WindowState = WindowState.Minimized;

[COLOR="green"]      'tell the app which is the main form - it is the form that will be shown automatically[/COLOR]
      app.MainForm = f;

      [COLOR="green"]'run the app. this method causes the form to be shown.
      [/COLOR]app.Run(Environment.GetCommandLineArgs());
    }
  }

After the form finishes showing, the Shown event handler runs:

VB.NET:
    private void MainForm_Shown(object sender, EventArgs e)
    {
      [COLOR="green"]'if its minimized, can only happen once; at app startup. nothing else minimizes the form
      'and it cannot be minimized by the user, esp not at this stage
      [/COLOR]if(this.WindowState == FormWindowState.Minimized) {

        [COLOR="green"]'hide the window so when we unminimize it it doesnt flick on screen
        [/COLOR]this.Visible = false;
        [COLOR="green"]'restore the window
        [/COLOR]this.WindowState = FormWindowState.Normal;

        [COLOR="green"]'calculate if the form is offscreen and if it is, move it on
        [/COLOR]Rectangle rect = Screen.GetWorkingArea(this);
        Rectangle form = new Rectangle(this.Location, this.Size);
        if(!rect.Contains(form)) {
          this.SetDesktopLocation((rect.Width - this.Width) / 2, (rect.Height - this.Height) / 2);
        }
      }
     [COLOR="green"] 'at this point a small, minimized window will be shown centre screen even thoguh I already restored it
      'if i double click the window, it maximizes and they disappears back to -32000, -32000[/COLOR]
    }

odd
 
I've gotta admit, looking at the code it would seem to be ok. As i said though this could be an issue with AnimateWindow. Have you tried it with ShowWindow instead.
 
I found a workaround:

Instead of minimizing my form, i simply move it off screen before it is shown. It shows Normal rather than Minimized but somewhere far away. Because I never minimize it, I dont seem to have the problem of it always wanting to return to a minimized state
 
Back
Top