c#阻止UserControl的屏幕截图

时间:2015-03-17 18:58:20

标签: c# .net wpf winforms

我公司的高管希望对我们的ui进行特定的自定义控制,以尽最大努力防止屏幕捕获。我在应用程序的顶级窗口级别使用SetWindowDisplayAffinityDWMEnableComposition实现了一个灵活的解决方案,以防止整个应用程序的屏幕截图,但前面提到的高管对此并不满意。他们只希望特定的UserControl阻止屏幕捕获,而不是整个应用程序。

自定义控件是一个.NET 2.0 Windows.Forms.UserControl,包含在4.5 WPF WindowsFormsHost中,由4.5 WPF窗口控件包含。

在我告诉高管去哪里之前,我想确定没有合理的方法来实现它。

所以,我的问题是:如何实现.NET 2.0 UserControl的屏幕捕获防护?

由于

3 个答案:

答案 0 :(得分:1)

我有个主意: 用户单击“ PrintScreen”,将从我的程序中捕获的内容复制到剪贴板。 所以,我所需要的就是:赶紧检查他是否包含图像。 如果是:我从剪贴板中删除了图像。

代码:

//definition a timer
public static Timer getImageTimer = new Timer();
[STAThread]
static void Main()
{
    getImageTimer.Interval = 500;
    getImageTimer.Tick += GetImageTimer_Tick;
    getImageTimer.Start();

    ......

}

private static void GetImageTimer_Tick(object sender, EventArgs e)
        {
            if (Clipboard.ContainsImage())//if clipboard contains an image
                Clipboard.Clear();//delete
        }

*,但可以避免程序运行。 (您需要知道您的程序是否是前台程序,然后检查剪贴板);

答案 1 :(得分:0)

可能能够捕获击键。

以下是我使用的方法,但成效有限:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if ((m_parent != null) && m_parent.ScreenCapture(ref msg)) {
    return true;
  } else {
    return base.ProcessCmdKey(ref msg, keyData);
  }
}

protected override bool ProcessKeyEventArgs(ref Message msg) {
  if ((m_parent != null) && m_parent.ScreenCapture(ref msg)) {
    return true;
  } else {
    return base.ProcessKeyEventArgs(ref msg);
  }
}

返回“True”应该告诉系统PrintScreen例程已被处理,但它仍然经常在剪贴板上找到数据。

正如您在m_parent.ScreenCapture的调用中所看到的,我所做的是将捕获内容保存到文件中,然后将其显示在我自己的自定义图像查看器中。

如果有帮助,这是我在m_parent.ScreenCapture中为自定义图像查看器创建的包装器:

public bool ScreenCapture(ref Message msg) {
  var WParam = (Keys)msg.WParam;
  if ((WParam == Keys.PrintScreen) || (WParam == (Keys.PrintScreen & Keys.Alt))) {
    ScreenCapture(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
    msg = new Message(); // erases the data
    return true;
  }
  return false;
}

public void ScreenCapture(string initialDirectory) {
  this.Refresh();
  var rect = new Rectangle(Location.X, Location.Y, Size.Width, Size.Height);
  var imgFile = Global.ScreenCapture(rect);
  //string fullName = null;
  string filename = null;
  string extension = null;
  if ((imgFile != null) && imgFile.Exists) {
    filename = Global.GetFilenameWithoutExt(imgFile.FullName);
    extension = Path.GetExtension(imgFile.FullName);
  } else {
    using (var worker = new BackgroundWorker()) {
      worker.DoWork += delegate(object sender, DoWorkEventArgs e) {
        Thread.Sleep(300);
        var bmp = new Bitmap(rect.Width, rect.Height);
        using (var g = Graphics.FromImage(bmp)) {
          g.CopyFromScreen(Location, Point.Empty, rect.Size); // WinForm Only
        }
        e.Result = bmp;
      };
      worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
        if (e.Error != null) {
          var err = e.Error;
          while (err.InnerException != null) {
            err = err.InnerException;
          }
          MessageBox.Show(err.Message, "Screen Capture", MessageBoxButtons.OK, MessageBoxIcon.Stop);
        } else if (e.Cancelled) {
        } else if (e.Result != null) {
          if (e.Result is Bitmap) {
            var bitmap = (Bitmap)e.Result;
            imgFile = new FileInfo(Global.GetUniqueFilenameWithPath(m_screenShotPath, "Screenshot", ".jpg"));
            filename = Global.GetFilenameWithoutExt(imgFile.FullName);
            extension = Path.GetExtension(imgFile.FullName);
            bitmap.Save(imgFile.FullName, ImageFormat.Jpeg);
          }
        }
      };
      worker.RunWorkerAsync();
    }
  }
  if ((imgFile != null) && imgFile.Exists && !String.IsNullOrEmpty(filename) && !String.IsNullOrEmpty(extension)) {
    bool ok = false;
    using (SaveFileDialog dlg = new SaveFileDialog()) {
      dlg.Title = "ACP Image Capture: Image Name, File Format, and Destination";
      dlg.FileName = filename;
      dlg.InitialDirectory = m_screenShotPath;
      dlg.DefaultExt = extension;
      dlg.AddExtension = true;
      dlg.Filter = "PNG Image|*.png|Jpeg Image (JPG)|*.jpg|GIF Image (GIF)|*.gif|Bitmap (BMP)|*.bmp" +
        "|EWM Image|*.emf|TIFF Image|*.tif|Windows Metafile (WMF)|*.wmf|Exchangable image file|*.exif";
      dlg.FilterIndex = 0;
      if (dlg.ShowDialog(this) == DialogResult.OK) {
        imgFile = imgFile.CopyTo(dlg.FileName, true);
        m_screenShotPath = imgFile.DirectoryName;
        ImageFormat fmtStyle;
        switch (dlg.FilterIndex) {
          case 2: fmtStyle = ImageFormat.Jpeg; break;
          case 3: fmtStyle = ImageFormat.Gif; break;
          case 4: fmtStyle = ImageFormat.Bmp; break;
          case 5: fmtStyle = ImageFormat.Emf; break;
          case 6: fmtStyle = ImageFormat.Tiff; break;
          case 7: fmtStyle = ImageFormat.Wmf; break;
          case 8: fmtStyle = ImageFormat.Exif; break;
          default: fmtStyle = ImageFormat.Png; break;
        }
        ok = true;
      }
    }
    if (ok) {
      string command = string.Format(@"{0}", imgFile.FullName);
      try { // try default image viewer
        var psi = new ProcessStartInfo(command);
        Process.Start(psi);
      } catch (Exception) {
        try { // try IE
          ProcessStartInfo psi = new ProcessStartInfo("iexplore.exe", command);
          Process.Start(psi);
        } catch (Exception) { }
      }
    }
  }
}
我多年前就写过,我现在不在那里工作。源代码仍然在我的云端驱动器中,这样我就可以利用我学过的技能(并忘记)。

该代码并不是为了让您完全完成,而只是为了向您展示一种方法。如果您需要任何帮助,请告诉我。

答案 2 :(得分:0)

不是灵丹妙药,但可能构成战略的一部分...... 如果您担心Windows剪切工具或其他已知的剪切工具,您可以订阅Windows事件以捕获SnippingTool.exe启动时的通知,然后隐藏您的应用程序直到它被关闭:

        var applicationStartWatcher = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
        applicationStartWatcher.EventArrived += (sender, args) =>
            {
                if (args.NewEvent.Properties["ProcessName"].Value.ToString().StartsWith("SnippingTool"))
                {
                    Dispatcher.Invoke(() => this.Visibility = Visibility.Hidden);
                }
            };
        applicationStartWatcher.Start();

        var applicationCloseWatcher = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStopTrace"));
        applicationCloseWatcher.EventArrived += (sender, args) =>
        {
            if (args.NewEvent.Properties["ProcessName"].Value.ToString().StartsWith("SnippingTool"))
            {
                Dispatcher.Invoke(() =>
                    {
                        this.Visibility = Visibility.Visible;
                        this.Activate();
                    });
            }
        };
        applicationCloseWatcher.Start();

您可能需要以管理员身份运行才能使用此代码。 ManagementEventWatcher位于System.Management程序集中。

这与处理打印屏幕键的一些策略相结合:例如this之类的内容可能至少使屏幕捕获变得困难。