繁体   English   中英

点击不起作用-SetWindowLong是正确的技术吗?

[英]click-through is not working - is SetWindowLong the proper technique?

我一直在为此苦苦挣扎,并查看了一些将其推荐为正确过程的stackoverflow帖子:

透明的窗口层是可点击的,始终位于顶部

在我的代码中,我几乎完全遵循这种技术。 但是,我的代码无法正常工作,我对此感到有些困惑。 我想知道我是否使用了错误的程序? 明确地说,我想要的效果是用户单击我的表单并访问其下方的内容。 例如,我在Visual Studio上运行。 如果我尝试单击该应用程序,则改为单击Visual Studio。

更新:

当我调用代码时,会发生以下两种情况之一(取决于我在哪里调用setwindowlong方法):

  1. 窗口不绘制
  2. 窗口已绘制,但可单击

选项1发生在我初始化组件之后立即运行代码时选项2发生在我初始化组件之后立即运行代码时

这是绘制我的表单之前的完整代码:

    [DllImport("user32.dll", SetLastError = true)]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [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);

    public frmPhoneQueueViewer()
    {
        InitializeComponent();
        // Set the form click-through
        int initialStyle = GetWindowLong(this.Handle, -20);
        SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);


        //Get height of taskbar to exclude it, then bind to lower right of screen
        int nTaskBarHeight = Screen.PrimaryScreen.Bounds.Bottom -Screen.PrimaryScreen.WorkingArea.Bottom;
        Rectangle workingArea = Screen.GetWorkingArea(this);
        this.Location = new Point(Screen.PrimaryScreen.Bounds.Right - this.Size.Width, workingArea.Bottom - Size.Height + nTaskBarHeight);
        this.TopMost = true;

        this.FormBorderStyle = FormBorderStyle.None;
        this.ControlBox = false;
        this.Text = string.Empty;
        this.ShowInTaskbar = false;


        PopulatePhoneQueueData();
    }

我们有WS_EX_TRANSPARENT = 0x20 ,它将使您的表单完全透明。此扩展样式是click through window所必需的。 因此,我们将有某种方法可以正常显示您的窗口(否则它是透明的,这就是您认为未绘制窗口的原因),我们可以使用win32 api函数SetLayeredWindowAttributes (在您的代码中声明)来完成此操作,或者只需设置Opacity属性即可你的形式。 顺便说一句,您应该重写CreateParams来初始化扩展样式,而无需声明和使用方法GetWindowLongSetWindowLong 这是应该起作用的代码(至少解决了您的问题: 未绘制窗口 ):

public frmPhoneQueueViewer()
{
    InitializeComponent();
    //The default Opacity = 1 won't show your form
    Opacity = 0.2f; //or even Opacity = 0.999 if you like
    //....
    //....
}
protected override CreateParams CreateParams {
    get {
         CreateParams cp = base.CreateParams;
         //WS_EX_LAYERED = 0x80000  WS_EX_TRANSPARENT = 0x20
         cp.ExStyle |= 0x80000 | 0x20;                
         return cp;
    }
}

注意 :这里发现了一件有趣的事情。 如果您在上面的代码中覆盖了CreateParams ,则Opacity=1不会显示您的表单(完全透明),您必须将Opacity更改为另一个值,例如0.2以使其部分透明,即使Opacity=0.9999也会显示您的表单(看起来不透明度为100%)。 但是,如果使用一些bool flag来防止在CreateParams初始化样式,并在以后使用UpdateStyles()应用样式,则当Opacity=1时,表单将显示OK,代码如下所示:

public frmPhoneQueueViewer()
{
    InitializeComponent();
    //The default Opacity = 1 will show your form normally
    Load += (s,e) => {
        appliedStyles = true;
        UpdateStyles();//Call this to apply the styles to make your window able to click through.
    };
    //....
    //....
}
bool appliedStyles;
protected override CreateParams CreateParams {
    get {
         CreateParams cp = base.CreateParams;
         //WS_EX_LAYERED = 0x80000  WS_EX_TRANSPARENT = 0x20
         if(appliedStyles) cp.ExStyle |= 0x80000 | 0x20;                
         return cp;
    }
}

设置其他窗口样式的正确方法是重写CreateParams getter。

这样,样式便会从创作中呈现出来。 SetWindowLong可能将它们设置得太迟而无法100%有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM