【问题标题】:How do I prevent print screen如何防止打印屏幕
【发布时间】:2010-10-01 16:15:48
【问题描述】:

我要求我正在开发的应用程序阻止用户轻松捕获屏幕内容。

我已告知没有可行的方法来完全防止这种情况发生,但我正在寻找方法来为该过程引入一些障碍。

我正在使用 C#/.NET 2.0 和 WinForms

【问题讨论】:

  • 哈哈。客户的要求总是那么好;)
  • 将螺丝刀插入用户键盘上的打印屏幕按钮。 :) 我靠,我靠!
  • 多么愚蠢的要求 - 只是说这是不可能的,任何“障碍”都是浪费时间
  • 雇佣一群令人生畏的人站在你的用户身后,同时拿着棒球棒。这应该可以防止他们对您的应用程序做任何不受欢迎的事情。

标签: c# .net winforms .net-2.0 c#-2.0


【解决方案1】:

你不能。

您可以做的最好的事情是在叠加层上渲染到硬件加速设备,类似于视频播放器过去所做的事情。基本上,您将整个窗口涂成蓝色,并将您的图形渲染到视频卡上,而在内部,视频卡将用图形替换蓝色。这样做的缺点是您必须放弃使用 winforms 控件,而且我不知道有任何方法可以轻松地使用 .NET 做到这一点。我认为如果您使用DirectShow.NET,他们的示例之一就是将您自己的图形放入流中。

即使完成所有这些操作,仍然可以获得屏幕截图。只需使用数码相机拍摄屏幕照片即可。

【讨论】:

  • 数码相机+1。用户可能在阁楼的某个地方有一张旧的宝丽来。用户使用 etch-a-sketch 捕获屏幕的奖励积分 :-)
  • 这会阻止我从使用该程序模拟另一台机器的机器上截取屏幕截图吗?
  • 我假设您的意思是虚拟机。我不知道这些是如何实现的。有可能它会起作用,但我对此表示怀疑。此外,Windows 7 渲染模式似乎意味着这不再可能了。
  • 至少下面的答案提供了相对清晰的方法来使屏幕捕获更难。
【解决方案2】:

来自here:

A. Windows 使用注册的热键实现 Print Screen。视窗 使用预定义的热键 IDHOT_SNAPDESKTOP 和 IDHOT_SNAPWINDOW 来 处理打印屏幕。这些对应于 Print Screen,它捕获 整个屏幕,以及 Alt+Print Screen,它只捕获 活动窗口。要禁用这些功能,您所要做的就是 注册热键,这会导致 Windows 向您的应用发送 用户按下任一热键时的 WM_HOTKEY 消息。您的 实现可以忽略消息绕过默认 屏幕捕获行为。一个很好的地方是在你的大型机中 类。

【讨论】:

  • 行不通。大多数截图工具也定义了自己的热键
  • 它会阻止内置打印屏幕工作吗?这够好吗?
  • 这和我的想法差不多。禁用打印屏幕会删除大部分屏幕截图。哎呀,如果他们真的想捕捉屏幕,他们可以很容易地拿一个数码相机,然后这样。
  • 我用 slimKEYS 进行了测试,将 PrintScreen 映射到其他东西(打开记事本),并且成功了。这意味着使用 PrintScreen vkey 代码调用 RegisterHotkey 将为您工作。我还测试了 Alt-PrintScreen。您必须同时注册两者,但不会阻止其他应用捕获...
  • 谁能为此提供代码示例?我正在尝试这样做,但我真的不知道该怎么做。
【解决方案3】:

FWIW,这是可能的。这是一些代码:

这将是您创建的 dll,然后从您的应用程序中调用 HookKeyboard 方法。我已经对其进行了测试,并且可以正常工作。当然,如果有人用相机拍照,这无济于事,但是,有道理。哎呀!

    namespace KeyboardHook
    {
        public class Hooker
        {

            [StructLayout(LayoutKind.Sequential)]
            public struct KBDLLHOOKSTRUCT
            {
                public int vkCode;
                public int scanCode;
                public int flags;
                public int time

;
            public int extraInfo;
        }

        public delegate int HookProc(int nCode, int wParam, IntPtr ptrKBDLLHOOKSTRUCT);


        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc callBack, IntPtr hMod, int threadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int CallNextHookEx(IntPtr hhk, int nCode, int wParam, IntPtr lParam);

        private static IntPtr kbh_Handle;
        private static HookProc kbh_HookProc;

        private const int VK_SNAPSHOT = 0x2C;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;
        private const int WH_KEYBOARD_LL = 13;

        private static int LowLevelKeyboardProc(int nCode, int wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                CallNextHookEx(kbh_Handle, nCode, wParam, lParam);
                return 0;
            }

            if (wParam == WM_KEYDOWN)
            {
                IntPtr kbdll = lParam;
                KBDLLHOOKSTRUCT kbdllstruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(kbdll, typeof(KBDLLHOOKSTRUCT));

                if (kbdllstruct.vkCode == VK_SNAPSHOT)
                    return -1;

            }

            return CallNextHookEx(kbh_Handle, nCode, wParam, lParam);
        }

        public static void HookKeyboard()
        {
            try
            {
                kbh_HookProc = LowLevelKeyboardProc;

                kbh_Handle = SetWindowsHookEx(WH_KEYBOARD_LL, kbh_HookProc, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);

                if (kbh_Handle != IntPtr.Zero)
                    System.Diagnostics.Debug.WriteLine(String.Format("It worked! HookHandle: {0}", kbh_Handle));
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(String.Format("ERROR: {0}", ex.Message));
            }
        }
    }
}

【讨论】:

  • 当然,对于 1,000,000 个屏幕抓取应用程序(包括 Windows 7 内置应用程序)中的任何一个都绝对没有用,并且可能会让您的应用程序被偏执的 AV 标记为键盘记录器。所以这很好。
  • “我正在寻找方法来为这个过程引入一些障碍。”这将是一个障碍,需要安装额外的软件。
  • “我要求我正在开发的应用程序阻止用户轻松捕获屏幕内容。” -- 截屏还是很“容易”的。
  • 等等...你刚刚把你的班级命名为“Hooker”吗?
【解决方案4】:

您可以尝试使用 msipc.dll 中提供的 IpcProtectWindow。

[DllImport("msipc.dll", SetLastError = false, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
internal static extern int IpcProtectWindow([In] IntPtr hwnd);

下载SDKfrom Microsoft

调用上面的函数并提供您要保护的表单的句柄。 (Form.Handle 属性)

【讨论】:

    【解决方案5】:

    这里有两种情况需要您担心。一个,当您的窗口/应用程序有焦点时,另一个当它没有焦点时。

    当它没有焦点时,您无能为力,即如果用户点击您的应用程序并点击桌面,则不会将密钥发送到您的应用程序,因此您将永远看不到它们。在这种情况下,您可以在您的应用程序失去焦点时最小化到托盘(或者,可能在表单上放置一个“空白”面板以防止用户在其上看到任何内容,这也会阻止打印屏幕的使用)。

    在另一种情况下,当您有焦点时,捕捉击键并检查它们。如果按下 Alt 键且按下 PrintScreen 键,请重置该值,以免出现打印屏幕。 (想一想,这可能行不通。我需要对其进行测试才能确定。)

    【讨论】:

    • 我对此投了反对票,因为该信息具有误导性——即使您是正确的,应用程序线程或其窗口在窗口失焦时不会接收定向键事件,记录在案的 WinAPI过程RegisterHotKey 允许调用者捕获键而不管焦点——即“系统范围”,这应该是OP 的主要兴趣。换句话说,窗口是否失焦在这里并没有什么实际意义,当然OP也不应该担心。
    【解决方案6】:

    您可以查看电影播放器​​的行为。我相信它们直接渲染到硬件表面(通过 DirectX)。我怀疑你需要这样做。

    【讨论】:

      【解决方案7】:

      这并不能真正回答问题,但请记住,存在捕获屏幕的工具,并且一个简单的相机会破坏一切。

      我的意思是好吧,你“必须”,但我会(但我还年轻,还是学生,所以我不太了解可以说什么)回答这只是愚蠢的。

      【讨论】:

        【解决方案8】:

        查看新技术 - sivizion.com,它们一起阻止打印屏幕 - 无法绕过它。如果有人想办法破解它,请在这里发帖,我做不到。我认为他们也许可了他们的技术,不确定,看看吧。

        【讨论】:

        • 很有趣,但真是让人头疼。
        【解决方案9】:

        好吧,您可以尝试捕获按钮,但我不确定这会奏效。

        一直让我烦恼的一件事是,每当我播放一部电影时,它都不会截屏。如果您可以通过单独的上下文进行渲染,那么拍照会很烦人。也许您可以通过类似的方式发送屏幕输出?

        【讨论】:

          【解决方案10】:

          有些应用程序可以从 OpenGL 和 DirectX 应用程序捕获屏幕! (取决于(它们用于录制游戏电影) 附言。 windows aero 是 DirectX

          http://www.fraps.com/ 我认为这就是应用程序

          【讨论】:

            【解决方案11】:

            您可以使用视觉密码术和利用视网膜持久性使任何随意的打印屏幕无用(有关详细信息,请参阅article,有关网络演示,请参阅bit.ly/vcrypto)。

            这个想法是在两个或多个随机噪声图像之间以高频率交替,这将通过视觉的持久性结合以显示内容。屏幕截图只会抓取一张图像,并带有无意义的随机噪音。

            这是以闪烁和引起用户头痛为代价的,可能会被拍摄屏幕照片的相机打败,或者被不太随意的用户打败,但会打败任何随意的屏幕捕捉或帧抓取.

            在学术意义上,可能偶尔有用!

            【讨论】:

              【解决方案12】:

              为时已晚,但有一个快速的解决方法, 只需在 MDI 表单中使用它
              设置表单TrueTopMost属性,然后在事件下面写 private void frmMDI_Deactivate(object sender, EventArgs e){Clipboard.Clear();}

              在打印屏幕后用户必须最小化应用程序,当用户最小化应用程序时,我们正在清除剪贴板。

              您可以在注销功能或屏幕移动或调整大小或任何其他需要的表单事件中使用它:)

              如果 TopMost 属性为 true,截图工具也无法通过此复制屏幕。

              是的,我们无法阻止用户从手机或摄像头等外部设备捕获屏幕。

              【讨论】:

                【解决方案13】:

                在 windows 窗体应用程序中,在窗体 keyup 事件中使用此代码,

                   if (e.KeyCode == Keys.PrintScreen)
                                {
                                    Clipboard.Clear();
                                }
                

                Form keypreview 应该是 TRUE

                【讨论】:

                  【解决方案14】:

                  Microsoft 开发了一个名为 SetWindowDisplayAffinity 的 API 来支持窗口内容保护。此功能使应用程序能够保护应用程序内容不被通过一组特定的公共操作系统功能和 API 捕获或复制
                  SetWindowDisplayAffinity(hWnd, WDA_MONITOR);

                  【讨论】:

                    【解决方案15】:

                    我使用Timer 对象和Clipboard.Clear() 方法解决了这个问题。

                    首先使用Interval=1Timer 添加到您的主窗体中(非常快),然后在其事件中添加以下代码:

                    Clipboard.Clear();
                    

                    【讨论】:

                    • 这看起来是一个非常低效的解决方案。 interval=1 每秒会触发 1000 次。除了使标准的复制和粘贴功能变得无用之外,这还会占用系统资源。
                    • 有些时候防止截屏很重要,你必须确定是否消耗系统资源或浪费屏幕上的一些有价值的东西!!!
                    • 我不怀疑防止屏幕捕获很重要。但肯定有更有效的方法来做到这一点。即使将 interval 设置为 1500 也会对您的代码进行重大改进,尽管我仍然觉得您的方法缺乏技巧。
                    猜你喜欢
                    • 2016-03-30
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-12-26
                    • 2014-12-09
                    • 1970-01-01
                    • 2011-03-09
                    相关资源
                    最近更新 更多