C# DPI-aware和Rect
我有个小问题,似乎找不到答案。我有一个应用程序,它可以获得特定的进程和窗口大小。唯一的问题是它占用了实际屏幕大小(用户看到的)的一个百分比 我想做一个应用程序的屏幕截图,但是如果我使用窗口的矩形,我会得到一个比它更小的屏幕,因为分辨率是125%。这意味着我输出的原始分辨率(C# DPI-aware和Rect,c#,bitmap,screenshot,rect,dpi-aware,C#,Bitmap,Screenshot,Rect,Dpi Aware,我有个小问题,似乎找不到答案。我有一个应用程序,它可以获得特定的进程和窗口大小。唯一的问题是它占用了实际屏幕大小(用户看到的)的一个百分比 我想做一个应用程序的屏幕截图,但是如果我使用窗口的矩形,我会得到一个比它更小的屏幕,因为分辨率是125%。这意味着我输出的原始分辨率(1280*800)比我的屏幕分辨率(1600*1000)小。您可以理解,这个小问题使我的程序不可靠。我的问题是如何解决这个问题 我已经创建了一个清单,我将DPIAware设置为true。我还在调试中禁用了VisualStudi
1280*800
)比我的屏幕分辨率(1600*1000
)小。您可以理解,这个小问题使我的程序不可靠。我的问题是如何解决这个问题
我已经创建了一个清单,我将DPIAware
设置为true。我还在调试中禁用了VisualStudio宿主。但这没用。我仍然得到相同的值和相同的问题。下面是我实际截屏的代码片段:
RECT Rect = new RECT();
System.Diagnostics.Process[] p = System.Diagnostics.Process.GetProcessesByName("Process");
ShowWindow(p[0].MainWindowHandle, 9);
SetForegroundWindow(p[0].MainWindowHandle);
if (GetWindowRect(p[0].MainWindowHandle, ref Rect))
{
var bmp = new Bitmap(Rect.Width, Rect.Height);
var graphics = Graphics.FromImage(bmp);
graphics.CopyFromScreen(Rect.Left, Rect.Top, 0, 0, new Size(Rect.Width, Rect.Height), CopyPixelOperation.SourceCopy);
bmp.Save(@"C:\Screenshots\temp1.png");
}
这给了我一个1280*800
的屏幕截图,不足以涵盖整个过程,即1600*1000
。因为屏幕坐标不正确,所以一切都关闭了。如果我把所有的数乘以1,25就可以了,但这不是一个解决方案,因为我不知道其他PC上的DPI设置是什么
编辑3:
我将发布包含RECT的完整代码
RECT Rect = new RECT();
System.Diagnostics.Process[] p = System.Diagnostics.Process.GetProcessesByName("LoLPatcherUx");
ShowWindow(p[0].MainWindowHandle, 9);
SetForegroundWindow(p[0].MainWindowHandle);
if (GetWindowRect(p[0].MainWindowHandle, ref Rect))
{
int processH = Rect.Bottom - Rect.Top;
int processW = Rect.Right - Rect.Left;
float processWidth;
float processHeight;
SizeF dpi = GetCurrentDpi();
// Calc the scale.
SizeF scale = new SizeF()
{
Width = dpi.Width / 96f,
Height = dpi.Height / 96f
};
// Scale the rectangle.
processWidth = Rect.Width * scale.Width;
processHeight = Rect.Height * scale.Height;
var bmp = new Bitmap(lolPatcherBreedte, lolPatcherHoogte);
Graphics graphics = Graphics.FromImage(bmp);
graphics.CopyFromScreen(Rect.Left, Rect.Top, 0, 0, new Size(processW, processH));
bmp.Save(@"C:\Screenshots\temp1.png");
}
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;
}
}
您可以通过获取当前的DPI设置
- 及
表单
和一个图形
对象(如果您的代码是在表单上下文之外执行的),即可获得这些信息:
用法:
if (GetWindowRect(p[0].MainWindowHandle, ref Rect))
{
var bmp = new Bitmap(Rect.Width, Rect.Height);
Graphics graphics = Graphics.FromImage(bmp);
// Use the helper function to get the current dpi.
SizeF dpi = GetCurrentDpi();
// Calc the scale.
SizeF scale = new SizeF()
{
Width = dpi.Width / 96f,
Height = dpi.Height / 96f
};
// Scale the rectangle.
Rect.Width *= scale.Width;
Rect.Height *= scale.Height;
graphics.CopyFromScreen(Rect.Left, Rect.Top, 0, 0, new Size(Rect.Width, Rect.Height), CopyPixelOperation.SourceCopy);
bmp.Save(@"C:\Screenshots\temp1.png");
}
演示:
class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hwnd, ref RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
static void Main(string[] args)
{
RECT rect = new RECT();
Process[] processes = System.Diagnostics.Process.GetProcessesByName("iexplore");
Process iexplore = processes.First();
ShowWindow(iexplore.MainWindowHandle, ShowWindowCommands.Restore);
SetForegroundWindow(iexplore.MainWindowHandle);
var result = GetWindowRect(iexplore.MainWindowHandle, ref rect);
RectangleF rectF = new RectangleF()
{
Location = new PointF(rect.Left, rect.Top),
Size = new SizeF(rect.Right - rect.Left + 1, rect.Bottom - rect.Top + 1)
};
var bmp = new Bitmap((int)rectF.Width, (int)rectF.Height);
Graphics graphics = Graphics.FromImage(bmp);
graphics.CopyFromScreen((int)rectF.Left, (int)rectF.Top, 0, 0, new Size((int)rectF.Width, (int)rectF.Height), CopyPixelOperation.SourceCopy);
bmp.Save(@"C:\temp\screenshot1.jpg", ImageFormat.Jpeg);
}
}
enum ShowWindowCommands
{
Hide = 0,
Normal = 1,
ShowMinimized = 2,
Maximize = 3,
ShowMaximized = 3,
ShowNoActivate = 4,
Show = 5,
Minimize = 6,
ShowMinNoActive = 7,
ShowNA = 8,
Restore = 9,
ShowDefault = 10,
ForceMinimize = 11
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
这不是dpiAware,除非你达到125%以上,否则它不会生效。这是相当奇怪的,你得到任何东西,这个过程需要时间来开始,创建和油漆它的窗口。ShowWindow()不足以确保完成此操作。样板文件是使用Process.WaitForInputIdle(),您可能需要使用Thread.Sleep()更长时间来冷却,因为这个过程行为古怪。我这里的代码只是发布在这里的一个片段。奇怪的是,其他一切都很好,但截屏是我无法得到正确的东西,因为这个奇怪的错误。我将尝试下面发布的解决方案,我希望能解决问题。我还想进一步发表评论。这个过程已经在运行了,如果我在代码中硬编码值(1600*1000),它就像阳光一样工作。这意味着它可以动态完成,对吗?实际上什么是
RECT
,如何包装它?你在哪里设置它的大小?见上面我添加了RECT的代码,这样你就可以更清楚地了解我在做什么。我真的不知道如何在上面的截图中使用它。。您能否详细说明如何在上面的代码段中实现这一点?我更新了示例。您需要输入当前的dpi值。这个小助手功能将为你得到他们。谢谢我要试试这个!所以我试了一下,它给了我96的宽度和高度。这意味着我的DPI为96。但这告诉我什么呢?这如何帮助我获得流程窗口的正确值?抱歉,我问了这些问题,但我有点被困在这里了(顺便问一下,你帮了我大忙,我只想谢谢你!
class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hwnd, ref RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
static void Main(string[] args)
{
RECT rect = new RECT();
Process[] processes = System.Diagnostics.Process.GetProcessesByName("iexplore");
Process iexplore = processes.First();
ShowWindow(iexplore.MainWindowHandle, ShowWindowCommands.Restore);
SetForegroundWindow(iexplore.MainWindowHandle);
var result = GetWindowRect(iexplore.MainWindowHandle, ref rect);
RectangleF rectF = new RectangleF()
{
Location = new PointF(rect.Left, rect.Top),
Size = new SizeF(rect.Right - rect.Left + 1, rect.Bottom - rect.Top + 1)
};
var bmp = new Bitmap((int)rectF.Width, (int)rectF.Height);
Graphics graphics = Graphics.FromImage(bmp);
graphics.CopyFromScreen((int)rectF.Left, (int)rectF.Top, 0, 0, new Size((int)rectF.Width, (int)rectF.Height), CopyPixelOperation.SourceCopy);
bmp.Save(@"C:\temp\screenshot1.jpg", ImageFormat.Jpeg);
}
}
enum ShowWindowCommands
{
Hide = 0,
Normal = 1,
ShowMinimized = 2,
Maximize = 3,
ShowMaximized = 3,
ShowNoActivate = 4,
Show = 5,
Minimize = 6,
ShowMinNoActive = 7,
ShowNA = 8,
Restore = 9,
ShowDefault = 10,
ForceMinimize = 11
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}