【问题标题】:How to capture screenshot without user32.dll which is unmanaged code如何在没有非托管代码的 user32.dll 的情况下捕获屏幕截图
【发布时间】:2015-02-24 17:29:14
【问题描述】:

概述 我正在尝试捕获外部应用程序的屏幕截图并将图像加载到 .NET PictureBox。

user32.dll 非托管代码 有很多使用 user32.dll 的示例,我正在寻找不使用 user32.dll 文件的 .NET 答案。

应用 #1 我在下面提供了用于演示目的的示例代码。当程序执行时,它会解析进程并将具有有效窗口标题的进程保存到下拉列表中。

当您从下拉列表中选择应用名称并单击按钮时,它将尝试捕获屏幕截图应用并加载到 .NET PictureBox 中。

Form1.cs

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms;

    namespace WindowsFormsApplication3
    {
        public partial class Form1 : Form
        {

            Dictionary<string, IntPtr> apps = new Dictionary<string, IntPtr>();

            public Form1()
            {
                InitializeComponent();

                foreach (Process process in Process.GetProcesses())
                {
                    if (string.IsNullOrEmpty(process.MainWindowTitle))
                        continue;

                    apps.Add(process.MainWindowTitle, process.MainWindowHandle);
                    comboBox1.Items.Add(process.MainWindowTitle);
                }
            }

            private void button1_Click(object sender, EventArgs e)
            {
                IntPtr intptr = apps[comboBox1.Items[comboBox1.SelectedIndex].ToString()];

                Graphics g = Graphics.FromHwnd(intptr);

                // get width and height of app #2
                int width = (int)g.VisibleClipBounds.Width;
                int height = (int)g.VisibleClipBounds.Height;

                Size s = new Size(width, height);

                // create new bitmap
                Bitmap wincapture = new Bitmap(width, height, g);

                // code tried.
                //g.CopyFromScreen(0, 0, 0, 0, new Size(width, height));
                //g.DrawImage(wincapture, 0, 0, width, height);

                // once App #2 has been captured, show image in picture box.
                pictureBox1.Image = wincapture;
            }
        }
    }

Form1.Designer.cs

    namespace WindowsFormsApplication3
    {
        partial class Form1
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Windows Form Designer generated code

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.pictureBox1 = new System.Windows.Forms.PictureBox();
                this.button1 = new System.Windows.Forms.Button();
                this.comboBox1 = new System.Windows.Forms.ComboBox();
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
                this.SuspendLayout();
                // 
                // pictureBox1
                // 
                this.pictureBox1.Location = new System.Drawing.Point(13, 13);
                this.pictureBox1.Name = "pictureBox1";
                this.pictureBox1.Size = new System.Drawing.Size(267, 183);
                this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
                this.pictureBox1.TabIndex = 0;
                this.pictureBox1.TabStop = false;
                // 
                // button1
                // 
                this.button1.Location = new System.Drawing.Point(102, 227);
                this.button1.Name = "button1";
                this.button1.Size = new System.Drawing.Size(82, 23);
                this.button1.TabIndex = 2;
                this.button1.Text = "View Ext App";
                this.button1.UseVisualStyleBackColor = true;
                this.button1.Click += new System.EventHandler(this.button1_Click);
                // 
                // comboBox1
                // 
                this.comboBox1.FormattingEnabled = true;
                this.comboBox1.Location = new System.Drawing.Point(13, 202);
                this.comboBox1.Name = "comboBox1";
                this.comboBox1.Size = new System.Drawing.Size(267, 21);
                this.comboBox1.TabIndex = 3;
                // 
                // Form1
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(292, 256);
                this.Controls.Add(this.comboBox1);
                this.Controls.Add(this.button1);
                this.Controls.Add(this.pictureBox1);
                this.Name = "Form1";
                this.Text = "App #1";
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
                this.ResumeLayout(false);

            }

            #endregion

            private System.Windows.Forms.PictureBox pictureBox1;
            private System.Windows.Forms.Button button1;
            private System.Windows.Forms.ComboBox comboBox1;
        }
    }

【问题讨论】:

  • 你当前的代码是做什么的?为什么不想使用非托管函数?看起来至少你需要 GetWindowRect。
  • 我希望代码能够捕获窗口? Graphics g = Graphics.FromHwnd(intptr);不知道如何复制到位图。
  • NightOwl,这个问题来自 2009 并使用 非托管代码。我希望使用 .NET 4,我们可能会有一些新类。
  • @CodeCaster 执行代码时,Form1() 方法循环遍历每个窗口进程,并将它们添加到具有窗口标题的下拉列表中。当您从下拉列表中选择标题并按下按钮时,它将尝试截取屏幕并将图像加载到 PictureBox 中。

标签: c# .net winforms .net-4.0 screenshot


【解决方案1】:

这是我在不使用 user32.dll 的情况下为应用程序截屏的代码。


使应用程序处于活动状态,并等待 20 以确保它已完成。

    Microsoft.VisualBasic.Interaction.AppActivate(ProcessId);
    Threading.Thread.Sleep(20);

为了捕获活动窗口,我使用了以下内容。添加延迟200,然后将剪贴板对象转换为图像。

    SendKeys.SendWait("%{PRTSC}");
    Threading.Thread.Sleep(200);
    IDataObject objData = Clipboard.GetDataObject();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-04
    • 2019-12-06
    • 1970-01-01
    • 2022-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多