Notification Window - Preventing the window from ever getting focus

前端 未结 3 1296
醉酒成梦
醉酒成梦 2020-12-19 04:41

I\'m having some issues getting a notification box to behave correctly in c#. Basically I\'m showing a boarderless form in the lower right hand side of the screen, which dis

相关标签:
3条回答
  • 2020-12-19 04:48

    I'm not looking for points here as the original poster already posted a solution that worked for them but I wanted to share my experience with this problem. Using the solution above (which is at the bottom of the question instead of in answer form) gives me a Win32Exception: Error creating window handle error. when using the WndProc code as it is posted there. The ShowWithoutActivation and CreateParams part works great to prevent activation of a form and still keep it topmost.

    I came up with an alternate solution to preventing a form from being clicked using SetWindowLong which makes the form transparent and therefore it can be clicked through and SetLayeredWindowAttributes which sets the transparency back to normal so you can see the form again but still retain the ability to click through the form.

    NOTE: You -CANNOT- interact with the form at all in this state and even trying to click the 'X' button will just click whatever is behind the form at that position so you will need to use code to close the form:

    public partial class Form1 : Form
    {
        private enum GWL : int
        {
            ExStyle = -20
        }
    
        private enum WS_EX : int
        {
            Transparent = 0x20,
            Layered = 0x80000
        }
    
        public enum LWA : int
        {
            ColorKey = 0x1,
            Alpha = 0x2
        }
    
        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    
        [DllImport("user32.dll")]
        static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
    
        protected override bool ShowWithoutActivation
        {
            get { return true; }
        }
    
        const int WS_EX_NOACTIVATE = 0x08000000;
        const int WS_EX_TOPMOST = 0x00000008;
    
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams param = base.CreateParams;
                param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
                param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
                return param;
            }
        }
    
        public Form1()
        {
            InitializeComponent();
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
            // Prevent form from showing up in taskbar which also prevents activation by Alt+Tab 
    
            this.ShowInTaskbar = false;
    
            // Allow the form to be clicked through so that the message never physically interferes with work being done on the computer 
    
            SetWindowLong(this.Handle, (int)GWL.ExStyle, (int)WS_EX.Layered | (int)WS_EX.Transparent);
    
            // Set the opacity of the form
    
            byte nOpacity = 255;    // 0 = invisible, 255 = solid, anything inbetween will show the form with transparency
            SetLayeredWindowAttributes(this.Handle, 0, nOpacity, (uint)LWA.Alpha);
        }
    }
    

    I was also able to get the original approach working by making a small change to the WndProc code above.

    NOTE: This also makes the form unclickable but the behavior is different in that you can actually click the min, max and 'X' buttons but nothing happens when you do. The mouse cursor also changes when you are at the edge of the form as if to resize but it doesn't allow resizing:

    public partial class Form1 : Form
    {
        protected override bool ShowWithoutActivation
        {
            get { return true; }
        }
    
        const int WS_EX_NOACTIVATE = 0x08000000;
        const int WS_EX_TOPMOST = 0x00000008;
    
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams param = base.CreateParams;
                param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
                param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
                return param;
            }
        }
    
        [DllImport("user32.dll")]
        private extern static IntPtr SetActiveWindow(IntPtr handle);
        private const int WM_ACTIVATE = 6;
        private const int WA_INACTIVE = 0;
    
        private const int WM_MOUSEACTIVATE = 0x0021;
        private const int MA_NOACTIVATEANDEAT = 0x0004;
    
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_MOUSEACTIVATE)
            {
                m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus
                return;
            }
            if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow
            {
                if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
                {
    
                    if (m.LParam != IntPtr.Zero)
                    {
                        SetActiveWindow(m.LParam);
                    }
                    else
                    {
                        // Could not find sender, just in-activate it.
                        SetActiveWindow(IntPtr.Zero);
                    }
    
                }
            }
            else
            {
                base.WndProc(ref m);
            }
        }
    
        public Form1()
        {
            InitializeComponent();
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
            // Prevent form from showing up in taskbar which also prevents activation by Alt+Tab 
    
            this.ShowInTaskbar = false;
        }
    }
    
    0 讨论(0)
  • 2020-12-19 04:57

    In WPF try this:

    ShowActivated="False"
    
    0 讨论(0)
  • 2020-12-19 05:04

    Possibly WS_EX_NOACTIVATE extended window style is what you are looking for. Window with this style is not activated when clicked. For example, Virtual Keyboard window has this style.

    To apply this style to window, override CreateParams function and change baseParams.ExStyle.

    0 讨论(0)
提交回复
热议问题