提高 PowerShell 中 C# PrintWindow() 的速度性能?

问题描述 投票:0回答:1

我已经成功实现了 PrintWindow 的 C# 代码以在 PowerShell 中使用(如下),但我想知道是否可以加快此过程。目前执行 PrintWindow 方法平均需要 80 毫秒。我想将其减少一半或大幅减少执行 PrintWindow 拍照所需的时间。

有人可以提供一些见解和可能的示例/更改,我可以将它们直接插入到现有代码中以提高 PrintWindow 的速度吗?

当前PrintWindow方法:


        $PrintWindowCode = @'
        using System; 
        using System.Runtime.InteropServices; 
        using System.Drawing;
        using System.Drawing.Imaging;

        public class ScreenCapture
        {

        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
        [DllImport("user32.dll")]
        public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);

        public Bitmap PrintWindow(IntPtr hwnd)    
        {       
            int PW_CLIENTONLY = 0x1;
            int PW_RENDERFULLCONTENT = 0x2; 
            RECT rc;        
            GetWindowRect(hwnd, out rc);

            Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);

            using (Graphics gfxBmp = Graphics.FromImage(bmp))
            {        
                IntPtr hdcBitmap = gfxBmp.GetHdc();       

                try
                {
                    PrintWindow(hwnd, hdcBitmap, PW_CLIENTONLY | PW_RENDERFULLCONTENT);
                }
                finally
                {
                    gfxBmp.ReleaseHdc(hdcBitmap);
                    gfxBmp.Dispose();
                }
            }

            string acPath = System.IO.Directory.GetCurrentDirectory();
            string currentDir = acPath;    
            System.IO.Directory.SetCurrentDirectory(currentDir);

            bmp.Save("TestOutput.tif", ImageFormat.Tiff);

            try {
                    return bmp;
            }
            finally {
                    bmp.Dispose();
                    System.IO.Directory.SetCurrentDirectory(acPath);
            }
     
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            private int _Left;
            private int _Top;
            private int _Right;
            private int _Bottom;

            public RECT(RECT Rectangle) : this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
            {
            }
            public RECT(int Left, int Top, int Right, int Bottom)
            {
                _Left = Left;
                _Top = Top;
                _Right = Right;
                _Bottom = Bottom;
            }

            public int X {
                get { return _Left; }
                set { _Left = value; }
            }
            public int Y {
                get { return _Top; }
                set { _Top = value; }
            }
            public int Left {
                get { return _Left; }
                set { _Left = value; }
            }
            public int Top {
                get { return _Top; }
                set { _Top = value; }
            }
            public int Right {
                get { return _Right; }
                set { _Right = value; }
            }
            public int Bottom {
                get { return _Bottom; }
                set { _Bottom = value; }
            }
            public int Height {
                get { return _Bottom - _Top; }
                set { _Bottom = value + _Top; }
            }
            public int Width {
                get { return _Right - _Left; }
                set { _Right = value + _Left; }
            }
            public Point Location {
                get { return new Point(Left, Top); }
                set {
                    _Left = value.X;
                    _Top = value.Y;
                }
            }
            public Size Size {
                get { return new Size(Width, Height); }
                set {
                    _Right = value.Width + _Left;
                    _Bottom = value.Height + _Top;
                }
            }

            public static implicit operator Rectangle(RECT Rectangle)
            {
                return new Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height);
            }
            public static implicit operator RECT(Rectangle Rectangle)
            {
                return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom);
            }
            public static bool operator ==(RECT Rectangle1, RECT Rectangle2)
            {
                return Rectangle1.Equals(Rectangle2);
            }
            public static bool operator !=(RECT Rectangle1, RECT Rectangle2)
            {
                return !Rectangle1.Equals(Rectangle2);
            }

            public override string ToString()
            {
                return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}";
            }

            public override int GetHashCode()
            {
                return ToString().GetHashCode();
            }

            public bool Equals(RECT Rectangle)
            {
                return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom;
            }

            public override bool Equals(object Object)
            {
                if (Object is RECT) {
                    return Equals((RECT)Object);
                } else if (Object is Rectangle) {
                    return Equals(new RECT((Rectangle)Object));
                }

                return false;
            }
          }

        }

'@

        # Loads/Adds User Add-Type (With correct Assemblies)
        Add-type $PrintWindowCode -ReferencedAssemblies 'System.Windows.Forms','System.Drawing' 

        # Creates the object for the Function (ScreenShotAC.ScreenCapture)
        $ScreenCapture = New-Object ScreenCapture

        # Use PrintWindow to grab screenshot
        $ScreenCapture.PrintWindow(((Get-Process -Name javaw).MainWindowHandle))

我研究了一些 C# 内存流方法,并偶然发现了一些可以加速加载图像/文件的位图处理的方法。但是,我只是缺乏对如何正确实施这一点的理解。

c# powershell screenshot
1个回答
0
投票

如果您想缩短代码加载时间,我建议您提前编译 C# 代码,这样您就不必在运行时编译它。

Add-Type
允许您指定输出程序集,因此本质上,您只需执行此过程一次。下面是将 C# 代码编译成程序集的代码,我添加了一些逻辑,以便编译与 PowerShell 5.1 和 PowerShell 7+ 兼容。

# CSharp code goes here (should stay same as before)
$PrintWindowCode = '...'

# Define the absolute path where to store your assembly:
$assemblyPath = 'path\to\destination\assembly.dll'

$refAssemblies = @(
    'System.Windows.Forms'
    'System.Drawing'

    if ($IsCoreCLR) {
        'System.Drawing.Common'
        $pwshLocation = Split-Path -Path ([psobject].Assembly.Location) -Parent
        $pwshRefAssemblyPattern = [IO.Path]::Combine($pwshLocation, 'ref', '*.dll')
        (Get-Item -Path $pwshRefAssemblyPattern).FullName
    }
)

$addTypeSplat = @{
    ReferencedAssemblies = $refAssemblies
    OutputAssembly       = $assemblyPath
    TypeDefinition       = $PrintWindowCode
}

Add-Type @addTypeSplat

现在您已经编译了代码,您只需将代码更新为:

# Define the absolute path where to store your assembly:
$assemblyPath = 'path\to\theStored\assembly.dll'

# Loads/Adds User Add-Type (With correct Assemblies)
Add-type -Path $assemblyPath

# Creates the object for the Function (ScreenShotAC.ScreenCapture)
$ScreenCapture = New-Object ScreenCapture

# Use PrintWindow to grab screenshot
$ScreenCapture.PrintWindow((Get-Process -Name javaw).MainWindowHandle)
© www.soinside.com 2019 - 2024. All rights reserved.