我已经成功实现了 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# 代码,这样您就不必在运行时编译它。
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)