Search code examples
c#winformstimerduplicatesshowdialog

.ShowDialog() shows twice


I have an annoying problem... I just wanted to show a dialog, but it's always showing twice... Here's the code:

    private void tmr_sysdt_Tick(object sender, EventArgs e)
    {
        lbl_time.Text = System.DateTime.Now.ToLongTimeString();
        lbl_date.Text = System.DateTime.Now.ToLongDateString();
        if (GetLastInputTime() > Program.timeout)
        {
            frm_lockscreen login= new frm_lockscreen();
            tmr_sysdt.Enabled = false;
            if (login.ShowDialog(this) == DialogResult.OK) tmr_sysdt.Enabled = true;
        }
    }

The tmr_sysdt.Interval is 1000.

The problem is simple - but unsolvable for me - the dialog is showing in duplicate (the second is coming up AT THE SAME TIME as the first).

I have no idea, so any idea will be appreciated :)

Thank you, and if you need more details please comment!

Ps.: Sorry for bad eng


EDIT: GetLastInputTime()

    [DllImport("user32.dll")]
    static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
    static uint GetLastInputTime()
    {
        uint idleTime = 0;
        LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
        lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
        lastInputInfo.dwTime = 0;

        uint envTicks = (uint)Environment.TickCount;

        if (GetLastInputInfo(ref lastInputInfo))
        {
            uint lastInputTick = lastInputInfo.dwTime;

            idleTime = envTicks - lastInputTick;
        }

        return ((idleTime > 0) ? (idleTime / 1000) : 0);
    }

    [StructLayout(LayoutKind.Sequential)]
    struct LASTINPUTINFO
    {
        public static readonly int SizeOf = Marshal.SizeOf(typeof(LASTINPUTINFO));

        [MarshalAs(UnmanagedType.U4)]
        public UInt32 cbSize;
        [MarshalAs(UnmanagedType.U4)]
        public UInt32 dwTime;
    }

Solution

  • Could you try this code? Just to make sure the logic in your handler isn't called twice at the same time:

        static bool busy = false;
        private void tmr_sysdt_Tick(object sender, EventArgs e)
        {
            if (busy)
            {
                return;
            }
            busy = true;
            try
            {
                lbl_time.Text = System.DateTime.Now.ToLongTimeString();
                lbl_date.Text = System.DateTime.Now.ToLongDateString();
                if (GetLastInputTime() > Program.timeout)
                {
                    frm_lockscreen login = new frm_lockscreen();
                    tmr_sysdt.Enabled = false;
                    if (login.ShowDialog(this) == DialogResult.OK) tmr_sysdt.Enabled = true;
                }
            }
            finally
            {
                busy = false;
            }
        }
    

    The problem you were having was that the code to check the last activity of the user and show the login box, was in a form that is created multiple times.
    So in fact, each of these 'main forms' were checking the user activity and showing the login box.

    By putting the busy bool as static, each instance of the 'main form' read this bool as the same value. Therefore, the check+show login only gets executed one time.

    I would suggest moving this code to a form you only create once, and keep open during the full lifetime of the application. (If you have such a form)