public class ControlImage
{
#region API
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SCROLLINFO
{
public uint cbSize;
public uint fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum ScrollBarInfoFlags
{
SIF_RANGE = 0x0001,
SIF_PAGE = 0x0002,
SIF_POS = 0x0004,
SIF_DISABLENOSCROLL = 0x0008,
SIF_TRACKPOS = 0x0010,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS)
}
public enum ScrollBarRequests
{
SB_LINEUP = 0,
SB_LINELEFT = 0,
SB_LINEDOWN = 1,
SB_LINERIGHT = 1,
SB_PAGEUP = 2,
SB_PAGELEFT = 2,
SB_PAGEDOWN = 3,
SB_PAGERIGHT = 3,
SB_THUMBPOSITION = 4,
SB_THUMBTRACK = 5,
SB_TOP = 6,
SB_LEFT = 6,
SB_BOTTOM = 7,
SB_RIGHT = 7,
SB_ENDSCROLL = 8
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetScrollInfo(IntPtr hwnd, int bar, ref SCROLLINFO si);
[DllImport("user32")]
public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool Rush);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern bool BitBlt(HandleRef hDC, int x, int y, int nWidth, int nHeight, HandleRef hSrcDC, int xSrc, int ySrc, int dwRop);
#endregion
private ControlImage() { }
private static int verticalScrollBarWidth = SystemInformation.VerticalScrollBarWidth;
private static int horizontalScrollBarHeight = SystemInformation.HorizontalScrollBarHeight;
/// <summary>
/// 支持呈现到指定的位图。
/// </summary>
public static void DrawToBitmap(Control control, Bitmap bitmap, Rectangle targetBounds)
{
if (bitmap == null)
{
throw new ArgumentNullException("bitmap");
}
if (((targetBounds.Width <= 0) || (targetBounds.Height <= 0)) || ((targetBounds.X < 0) || (targetBounds.Y < 0)))
{
throw new ArgumentException("targetBounds");
}
Bitmap image = new Bitmap(control.Width, control.Height, bitmap.PixelFormat);
using (Graphics graphics = Graphics.FromImage(image))
{
IntPtr hdc = graphics.GetHdc();
SendMessage(new HandleRef(control, control.Handle), 0x317, hdc, (IntPtr)30);
using (Graphics graphics2 = Graphics.FromImage(bitmap))
{
IntPtr handle = graphics2.GetHdc();
BitBlt(new HandleRef(graphics2, handle), 0, 0, control.Width, control.Height, new HandleRef(graphics, hdc), targetBounds.X, targetBounds.Y, 0xcc0020);
graphics2.ReleaseHdcInternal(handle);
}
graphics.ReleaseHdcInternal(hdc);
}
}
/// <summary>
/// 获取图形 有滚动截图功能
/// </summary>
public static Bitmap GetImage(Control control)
{
Point scrollMaxInfo = GetScrollPoint(control);
Size controlMaxSize = GetControlSize(control, scrollMaxInfo);
Bitmap bitmap = new Bitmap(controlMaxSize.Width, controlMaxSize.Height);
if (scrollMaxInfo.IsEmpty)
{
DrawToBitmap(control, bitmap, new Rectangle(0, 0, control.Width, control.Height));
return bitmap;
}
Graphics g = Graphics.FromImage(bitmap);
Bitmap tempBitmap = new Bitmap(control.Width - verticalScrollBarWidth, control.Height - horizontalScrollBarHeight);
int stepWidth = GetScrollNumber(control.Width - verticalScrollBarWidth, scrollMaxInfo.X);
int stepHeight = GetScrollNumber(control.Height - horizontalScrollBarHeight, scrollMaxInfo.Y);
int widthPos = 0;
int heightPos = 0;
MoveBar(0, 0, control);
for (int i = 0; i < stepWidth; i++)
{
heightPos = 0;
MoveBar(1, 0, control);
for (int z = 0; z < stepHeight; z++)
{
control.DrawToBitmap(tempBitmap, new Rectangle(0, 0, control.Width - verticalScrollBarWidth, control.Height - horizontalScrollBarHeight));
g.DrawImage(tempBitmap, widthPos, heightPos);
MoveBar(1, control.Height - horizontalScrollBarHeight + heightPos, control);
heightPos = GetScrollPoint(1, control);
}
MoveBar(0, control.Width - verticalScrollBarWidth + widthPos, control);
widthPos = GetScrollPoint(0, control);
}
g.Dispose();
tempBitmap.Dispose();
return bitmap;
}
/// <summary>
/// 获取目前滚动条位置
/// </summary>
/// <param name="bar"></param>
/// <param name="control"></param>
/// <returns></returns>
private static int GetScrollPoint(int bar, Control control)
{
SCROLLINFO scrollInfo = new SCROLLINFO();
scrollInfo.cbSize = (uint)Marshal.SizeOf(scrollInfo);
scrollInfo.fMask = (uint)ScrollBarInfoFlags.SIF_ALL;
GetScrollInfo(control.Handle, bar, ref scrollInfo);
return scrollInfo.nPos;
}
/// <summary>
/// 获取循环几次获得图形
/// </summary>
private static int GetScrollNumber(int controlNumber, int scrollMaxInfoNumber)
{
return (int)Math.Ceiling(scrollMaxInfoNumber / (double)controlNumber) + 1;
}
/// <summary>
/// 获得控件不需要滚动条的宽和高(最终图形大小)
/// </summary>
private static Size GetControlSize(Control control, Point scrollMaxInfo)
{
return new Size(control.Size.Width + scrollMaxInfo.X - verticalScrollBarWidth,
control.Size.Height + scrollMaxInfo.Y - horizontalScrollBarHeight);
}
/// <summary>
/// 获取控件滚动条数据
/// </summary>
private static Point GetScrollPoint(Control control)
{
verticalScrollBarWidth = SystemInformation.VerticalScrollBarWidth;
horizontalScrollBarHeight = SystemInformation.HorizontalScrollBarHeight;
Point maxScroll = new Point();
SCROLLINFO scrollInfo = new SCROLLINFO();
scrollInfo.cbSize = (uint)Marshal.SizeOf(scrollInfo);
scrollInfo.fMask = (uint)ScrollBarInfoFlags.SIF_ALL;
GetScrollInfo(control.Handle, 1, ref scrollInfo);
if ((int)scrollInfo.nPage == 0)
{
maxScroll.Y = 0;
verticalScrollBarWidth = 0;
}
else
{
maxScroll.Y = scrollInfo.nMax - (int)scrollInfo.nPage;
}
GetScrollInfo(control.Handle, 0, ref scrollInfo);
if ((int)scrollInfo.nPage == 0)
{
maxScroll.X = 0;
horizontalScrollBarHeight = 0;
}
else
{
maxScroll.X = scrollInfo.nMax - (int)scrollInfo.nPage;
}
return maxScroll;
}
/// <summary>
/// 移动控件滚动条位置
/// </summary>
private static void MoveBar(int bar, int nPose, Control control)
{
if (bar == 0)
{
SetScrollPos(control.Handle, 0, nPose, true);
SendMessage(control.Handle, 0x0114, (int)ScrollBarRequests.SB_THUMBPOSITION, 0);
}
else
{
SetScrollPos(control.Handle, 1, nPose, true);
SendMessage(control.Handle, 0x0115, (int)ScrollBarRequests.SB_THUMBPOSITION, 0);
}
}
}