You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#开发MAC地址悬浮窗:如何实现覆盖全屏应用?

问题:C#悬浮窗无法覆盖全屏应用的解决办法

我给在投注站做现场技术的姐夫开发了个悬浮窗程序,用来显示设备MAC地址,帮他和同事提高效率。找总部申请同款程序要等至少一年,他老板已经批准我来开发。现在用C#写完了,但悬浮窗盖不住全屏应用,有没有简单的解决办法?

现有实现代码

using System;
using System.Net.NetworkInformation;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using Timer = System.Windows.Forms.Timer;

namespace TransparentOverlay {
    public partial class DisplayMac : Form {
        private Label macLabel;

        public DisplayMac() {
            InitializeComponent();
            InitializeUI();
            ShowMACAddress();
            SetForegroundWindow(this.Handle);
        }

        private void InitializeUI() {
            FormBorderStyle = FormBorderStyle.None;
            BackColor = System.Drawing.Color.Black; // Set the color to the stroke color
            TransparencyKey = System.Drawing.Color.Blue;
            Size = new System.Drawing.Size(200, 30);
            StartPosition = FormStartPosition.Manual;
            Location = new System.Drawing.Point(Screen.PrimaryScreen.WorkingArea.Width - Width, Screen.PrimaryScreen.WorkingArea.Height - Height);

            macLabel = new Label {
                Text = "MAC Address: ",
                Location = new System.Drawing.Point(10, 10),
                AutoSize = true,
                ForeColor = System.Drawing.Color.White,
                BackColor = System.Drawing.Color.Black,
            };

            Controls.Add(macLabel);    // Then add the main label on top
        }

        private void ShowMACAddress() {
            string macAddress = GetMACAddress();
            macLabel.Text += macAddress;
            Timer timer = new Timer {
                Interval = 1000 // Update every 1000 milliseconds (1 second)
            };
            timer.Tick += (sender, e) => macLabel.Text = "MAC Address: " + GetMACAddress();
            timer.Start();

            SetWindowExTransparent(this.Handle);
        }

        private string GetMACAddress() {
            string mac = string.Empty;
            foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
                if (nic.NetworkInterfaceType != NetworkInterfaceType.Loopback && nic.OperationalStatus == OperationalStatus.Up) {
                    byte[] physicalAddressBytes = nic.GetPhysicalAddress().GetAddressBytes();
                    mac = string.Join(":", physicalAddressBytes.Select(b => b.ToString("X2")));
                    break;
                }
            }
            return mac;
        }

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        private const int WS_EX_LAYERED = 0x80000;
        private const int WS_EX_TRANSPARENT = 0x20;
        private const uint SWP_NOMOVE = 0x2;
        private const uint SWP_NOSIZE = 0x1;
        private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);

        private const uint LWA_COLORKEY = 0x1;
        private const uint LWA_ALPHA = 0x2;

        private void SetWindowExTransparent(IntPtr handle) {
            SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
            SetLayeredWindowAttributes(handle, 0, 128, LWA_ALPHA);
            SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle, GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT);
        }

        private const int GWL_EXSTYLE = -20;

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

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

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);


        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new DisplayMac());
        }
    }
}

解决步骤

要让悬浮窗稳定覆盖全屏应用,需要从窗口层级、样式优先级两个方面调整,以下是具体修改:

1. 添加关键窗口扩展样式

在类中新增两个常量:

private const int WS_EX_TOOLWINDOW = 0x00000080; // 标记为工具窗口,避免被全屏应用忽略
private const int WS_EX_NOACTIVATE = 0x08000000; // 窗口不获取焦点,始终保持在顶层

2. 修正SetWindowExTransparent方法的执行顺序

原方法的调用顺序错误,导致置顶效果失效,修改后确保先设置扩展样式,再应用置顶和透明度:

private void SetWindowExTransparent(IntPtr handle)
{
    // 先获取并更新扩展样式
    int exStyle = GetWindowLong(handle, GWL_EXSTYLE);
    exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE;
    SetWindowLong(handle, GWL_EXSTYLE, exStyle);

    // 设置窗口透明度
    SetLayeredWindowAttributes(handle, 0, 128, LWA_ALPHA);

    // 强制窗口置顶,添加SWP_SHOWWINDOW确保窗口正常显示
    SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}

3. 绑定到桌面窗口(针对硬件加速全屏应用)

如果是DirectX/OpenGL类的全屏应用,需要把悬浮窗绑定到桌面窗口,避免被独占模式屏蔽:

// 新增DllImport声明
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetDesktopWindow();

然后在Form的构造函数中添加:

public DisplayMac() {
    InitializeComponent();
    InitializeUI();
    ShowMACAddress();
    // 绑定到桌面窗口
    SetParent(this.Handle, GetDesktopWindow());
    SetForegroundWindow(this.Handle);
}

4. 移除冗余的TransparencyKey设置

原代码中同时使用了TransparencyKey和分层窗口透明度,可能导致冲突,建议删除:

// 从InitializeUI方法中删除这一行
// TransparencyKey = System.Drawing.Color.Blue;

验证效果

修改后重新编译运行,悬浮窗应该能稳定覆盖在各类全屏应用上方,同时保持MAC地址的实时更新。

内容的提问来源于stack exchange,提问作者zeebaah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 19:34:52