如何防止打印屏幕

时间:2022-04-29 21:13:22

I have a requirement that an application I am working on prevent the user from being able to easily capture the contents of the screen.

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

I have communicated that there is no feasible way to completely prevent this from happening, but I'm looking for methods to introduce some hurdles to the process.

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

I'm using C#/.NET 2.0 and WinForms

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

14 个解决方案

#1


You can't.

The best you can do is render to a hardware accelerated device on an overlay, similar to what video players used to do. Basically, you paint your entire window blue, and render your graphics onto the video card, and internally the video card will replace the blue with the graphics. The downside to this is you have to give up using winforms controls, and I don't know of any way to do this with .NET easily. I think if you use DirectShow.NET, one of their samples is putting your own graphics into a stream.

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

Even after doing all of that, it's still possible to get a screenshot. Just take a picture of the screen with a digital camera.

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

#2


From here:

A. Windows implements Print Screen using a registered hotkey. Windows uses the predefined hotkeys IDHOT_SNAPDESKTOP and IDHOT_SNAPWINDOW to handle Print Screen. These correspond to Print Screen, which captures the entire screen, and Alt+Print Screen, which captures only the active window. To disable these functions all you have to do is register the hotkeys, which causes Windows to send your app a WM_HOTKEY message when the user presses either hotkey. Your implementation can ignore the message to bypass the default screen-capture behavior. A good place to do it is in your mainframe class.

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

#3


You'll have two cases here that you need to worry about. One, when your window/application has focus, the other when it doesn't have focus.

你需要担心的是这里有两个案例。一,当你的窗口/应用程序有焦点时,另一个当它没有焦点时。

When it doesn't have focus, there's not a whole lot you can do, i.e. if the user clicks off of your app and onto the desktop, keys aren't sent to your app so you'll never see them. In that case, you can minimize to the tray when your app loses focus (or, perhaps, place a "blank" panel over the form to prevent users from seeing anything on it which will also prevent a print-screen from being useful).

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

In the other case, when you have focus, capture keystrokes and examine them. If the Alt key is down and the PrintScreen key is down, reset the value so that a print-screen doesn't occur. (Come to think of it, that may not work. I'd need to test it to be sure.)

在另一种情况下,当您有焦点时,捕获击键并检查它们。如果Alt键关闭且PrintScreen键关闭,请重置该值,以便不会出现打印屏幕。 (想想看,它可能不起作用。我需要测试它才能确定。)

#4


You could look into what movie players do. I believe they render directly to a hardware surface (via DirectX). I suspect that you'd need to do this.

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

#5


Perhaps this article might be of use:

也许这篇文章可能有用:

Disabling Print Screen, Calling Derived Destructors and More

禁用打印屏幕,调用派生的析构函数等

#6


FWIW, it is possible. Here's some code:

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

This would be a dll that you create, then call the HookKeyboard method from your application. I've tested it and it works. Granted, if someone takes a picture with a camera it can't help, but, point made. NYAH!

这将是您创建的DLL,然后从您的应用程序调用HookKeyboard方法。我测试了它,它的工作原理。当然,如果有人用相机拍照,它无能为力,但是,点了点。 NYAH!

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

#7


This doesn't really answer the questions, but keep in mind that there exists tools to capture screen, and that a simple camera breaks everything.

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

I mean ok you "have to", but I would (but I'm young and still student, so I don't know much about what can be said) answer that this is just stupid.

我的意思是你“必须”,但我会(但我还年轻,仍然是学生,所以我不知道可以说什么)回答这只是愚蠢。

#8


Check out the new tech - sivizion.com, they prevent print screen all together - no way to bypass it. If anyone will figure out a way how to hack it, please post here, I couldn't. I think they also license their tech, not sure, check it out.

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

#9


You can try using IpcProtectWindow provided in msipc.dll.

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

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

Download the SDK from Microsoft

从Microsoft下载SDK

Call the function above and provide the handle of the form you would like to protect. (Form.Handle property)

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

#10


Well, you could try capturing the button, but I'm not sure how well that will work.

好吧,你可以尝试捕捉按钮,但我不确定它会有多好用。

One thing that always annoyed me was that whenever I played a movie, it would never take screenshots of it. If you can render through a separate context, it would make it really annoying to take a picture of it. Perhaps you can send your screen output through something like that?

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

#11


There are applications that can capture the screen from OpenGL and DirectX apps ! (depending (they are used for recording game movies) ps. windows aero is DirectX

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

http://www.fraps.com/ i think thats the application

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

#12


You can make any casual Print Screen useless using Visual Cryptography and taking advantage of retinal persistence (see this article for details, and bit.ly/vcrypto for a web demo).

您可以使用Visual Cryptography并利用视网膜持久性使任何休闲Print Screen无用(有关详细信息,请参阅此文章,对于Web演示,请参阅bit.ly/vcrypto)。

The idea is to alternate at high frequency between two or more random noise images, that will combine through persistence of vision to reveal the content. A screen capture will only grab one image, with meaningless random noise.

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

This comes at the cost of flickering and inducing user headaches, can be defeated by a camera taking a picture of the screen, or by a less casual user that knows photoshop, but will defeat any kind of casual screen capture or frame grabbing.

这是以闪烁和引起用户头痛为代价的,可以通过拍摄屏幕照片的相机或者知道photoshop的不那么随意的用户来击败,但是会击败任何类型的随意屏幕捕获或帧抓取。

Might occasionally be useful, in an academic meaning of the term!

这个术语的学术意义可能偶尔会有用!

#13


It is too late but there is a quick work around, Simply use it in MDI form
Set TopMost Property of form True, then write below event private void frmMDI_Deactivate(object sender, EventArgs e){Clipboard.Clear();}

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

after taking print screen user have to minimize the application, the moment user minimize the app, we are clearing clipboard.

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

you can use this in logout function or when screen move or resize or any other form event as required :)

您可以在注销功能或屏幕移动或调整大小或任何其他形式事件时使用此:)

Snipping tool also can't copy screens by this if TopMost Property is true.

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

Yes we can't stop user from capturing screen from external device like phone or cam.

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

#14


I solved it using a Timer object and Clipboard.Clear() method.

我使用Timer对象和Clipboard.Clear()方法解决了它。

First add a Timer to your main form with Interval=1 (Very fast), then add the following code in its event:

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

Clipboard.Clear();

#1


You can't.

The best you can do is render to a hardware accelerated device on an overlay, similar to what video players used to do. Basically, you paint your entire window blue, and render your graphics onto the video card, and internally the video card will replace the blue with the graphics. The downside to this is you have to give up using winforms controls, and I don't know of any way to do this with .NET easily. I think if you use DirectShow.NET, one of their samples is putting your own graphics into a stream.

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

Even after doing all of that, it's still possible to get a screenshot. Just take a picture of the screen with a digital camera.

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

#2


From here:

A. Windows implements Print Screen using a registered hotkey. Windows uses the predefined hotkeys IDHOT_SNAPDESKTOP and IDHOT_SNAPWINDOW to handle Print Screen. These correspond to Print Screen, which captures the entire screen, and Alt+Print Screen, which captures only the active window. To disable these functions all you have to do is register the hotkeys, which causes Windows to send your app a WM_HOTKEY message when the user presses either hotkey. Your implementation can ignore the message to bypass the default screen-capture behavior. A good place to do it is in your mainframe class.

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

#3


You'll have two cases here that you need to worry about. One, when your window/application has focus, the other when it doesn't have focus.

你需要担心的是这里有两个案例。一,当你的窗口/应用程序有焦点时,另一个当它没有焦点时。

When it doesn't have focus, there's not a whole lot you can do, i.e. if the user clicks off of your app and onto the desktop, keys aren't sent to your app so you'll never see them. In that case, you can minimize to the tray when your app loses focus (or, perhaps, place a "blank" panel over the form to prevent users from seeing anything on it which will also prevent a print-screen from being useful).

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

In the other case, when you have focus, capture keystrokes and examine them. If the Alt key is down and the PrintScreen key is down, reset the value so that a print-screen doesn't occur. (Come to think of it, that may not work. I'd need to test it to be sure.)

在另一种情况下,当您有焦点时,捕获击键并检查它们。如果Alt键关闭且PrintScreen键关闭,请重置该值,以便不会出现打印屏幕。 (想想看,它可能不起作用。我需要测试它才能确定。)

#4


You could look into what movie players do. I believe they render directly to a hardware surface (via DirectX). I suspect that you'd need to do this.

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

#5


Perhaps this article might be of use:

也许这篇文章可能有用:

Disabling Print Screen, Calling Derived Destructors and More

禁用打印屏幕,调用派生的析构函数等

#6


FWIW, it is possible. Here's some code:

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

This would be a dll that you create, then call the HookKeyboard method from your application. I've tested it and it works. Granted, if someone takes a picture with a camera it can't help, but, point made. NYAH!

这将是您创建的DLL,然后从您的应用程序调用HookKeyboard方法。我测试了它,它的工作原理。当然,如果有人用相机拍照,它无能为力,但是,点了点。 NYAH!

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

#7


This doesn't really answer the questions, but keep in mind that there exists tools to capture screen, and that a simple camera breaks everything.

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

I mean ok you "have to", but I would (but I'm young and still student, so I don't know much about what can be said) answer that this is just stupid.

我的意思是你“必须”,但我会(但我还年轻,仍然是学生,所以我不知道可以说什么)回答这只是愚蠢。

#8


Check out the new tech - sivizion.com, they prevent print screen all together - no way to bypass it. If anyone will figure out a way how to hack it, please post here, I couldn't. I think they also license their tech, not sure, check it out.

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

#9


You can try using IpcProtectWindow provided in msipc.dll.

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

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

Download the SDK from Microsoft

从Microsoft下载SDK

Call the function above and provide the handle of the form you would like to protect. (Form.Handle property)

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

#10


Well, you could try capturing the button, but I'm not sure how well that will work.

好吧,你可以尝试捕捉按钮,但我不确定它会有多好用。

One thing that always annoyed me was that whenever I played a movie, it would never take screenshots of it. If you can render through a separate context, it would make it really annoying to take a picture of it. Perhaps you can send your screen output through something like that?

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

#11


There are applications that can capture the screen from OpenGL and DirectX apps ! (depending (they are used for recording game movies) ps. windows aero is DirectX

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

http://www.fraps.com/ i think thats the application

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

#12


You can make any casual Print Screen useless using Visual Cryptography and taking advantage of retinal persistence (see this article for details, and bit.ly/vcrypto for a web demo).

您可以使用Visual Cryptography并利用视网膜持久性使任何休闲Print Screen无用(有关详细信息,请参阅此文章,对于Web演示,请参阅bit.ly/vcrypto)。

The idea is to alternate at high frequency between two or more random noise images, that will combine through persistence of vision to reveal the content. A screen capture will only grab one image, with meaningless random noise.

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

This comes at the cost of flickering and inducing user headaches, can be defeated by a camera taking a picture of the screen, or by a less casual user that knows photoshop, but will defeat any kind of casual screen capture or frame grabbing.

这是以闪烁和引起用户头痛为代价的,可以通过拍摄屏幕照片的相机或者知道photoshop的不那么随意的用户来击败,但是会击败任何类型的随意屏幕捕获或帧抓取。

Might occasionally be useful, in an academic meaning of the term!

这个术语的学术意义可能偶尔会有用!

#13


It is too late but there is a quick work around, Simply use it in MDI form
Set TopMost Property of form True, then write below event private void frmMDI_Deactivate(object sender, EventArgs e){Clipboard.Clear();}

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

after taking print screen user have to minimize the application, the moment user minimize the app, we are clearing clipboard.

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

you can use this in logout function or when screen move or resize or any other form event as required :)

您可以在注销功能或屏幕移动或调整大小或任何其他形式事件时使用此:)

Snipping tool also can't copy screens by this if TopMost Property is true.

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

Yes we can't stop user from capturing screen from external device like phone or cam.

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

#14


I solved it using a Timer object and Clipboard.Clear() method.

我使用Timer对象和Clipboard.Clear()方法解决了它。

First add a Timer to your main form with Interval=1 (Very fast), then add the following code in its event:

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

Clipboard.Clear();