WindowFramebuffer.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Avalonia.Controls.Platform.Surfaces;
  4. using Avalonia.Platform;
  5. using Avalonia.Win32.Interop;
  6. using PixelFormat = Avalonia.Platform.PixelFormat;
  7. namespace Avalonia.Win32
  8. {
  9. public class WindowFramebuffer : ILockedFramebuffer
  10. {
  11. private readonly IntPtr _handle;
  12. private IntPtr _pBitmap;
  13. private UnmanagedMethods.BITMAPINFOHEADER _bmpInfo;
  14. public WindowFramebuffer(IntPtr handle, int width, int height)
  15. {
  16. if (width <= 0)
  17. throw new ArgumentException("width is less than zero");
  18. if (height <= 0)
  19. throw new ArgumentException("height is less than zero");
  20. _handle = handle;
  21. _bmpInfo.Init();
  22. _bmpInfo.biPlanes = 1;
  23. _bmpInfo.biBitCount = 32;
  24. _bmpInfo.Init();
  25. _bmpInfo.biWidth = width;
  26. _bmpInfo.biHeight = -height;
  27. _pBitmap = Marshal.AllocHGlobal(width * height * 4);
  28. }
  29. ~WindowFramebuffer()
  30. {
  31. Deallocate();
  32. }
  33. public IntPtr Address => _pBitmap;
  34. public int RowBytes => Width * 4;
  35. public PixelFormat Format => PixelFormat.Bgra8888;
  36. public Size Dpi
  37. {
  38. get
  39. {
  40. if (UnmanagedMethods.ShCoreAvailable)
  41. {
  42. uint dpix, dpiy;
  43. var monitor = UnmanagedMethods.MonitorFromWindow(_handle,
  44. UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST);
  45. if (UnmanagedMethods.GetDpiForMonitor(
  46. monitor,
  47. UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI,
  48. out dpix,
  49. out dpiy) == 0)
  50. {
  51. return new Size(dpix, dpiy);
  52. }
  53. }
  54. return new Size(96, 96);
  55. }
  56. }
  57. public int Width => _bmpInfo.biWidth;
  58. public int Height => -_bmpInfo.biHeight;
  59. public void DrawToDevice(IntPtr hDC, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
  60. int height = -1)
  61. {
  62. if(_pBitmap == IntPtr.Zero)
  63. throw new ObjectDisposedException("Framebuffer");
  64. if (width == -1)
  65. width = Width;
  66. if (height == -1)
  67. height = Height;
  68. UnmanagedMethods.SetDIBitsToDevice(hDC, destX, destY, (uint) width, (uint) height, srcX, srcY,
  69. 0, (uint)Height, _pBitmap, ref _bmpInfo, 0);
  70. }
  71. public bool DrawToWindow(IntPtr hWnd, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
  72. int height = -1)
  73. {
  74. if (_pBitmap == IntPtr.Zero)
  75. throw new ObjectDisposedException("Framebuffer");
  76. if (hWnd == IntPtr.Zero)
  77. return false;
  78. IntPtr hDC = UnmanagedMethods.GetDC(hWnd);
  79. if (hDC == IntPtr.Zero)
  80. return false;
  81. DrawToDevice(hDC, destX, destY, srcX, srcY, width, height);
  82. UnmanagedMethods.ReleaseDC(hWnd, hDC);
  83. return true;
  84. }
  85. public void Dispose()
  86. {
  87. //It's not an *actual* dispose. This call means "We are done drawing"
  88. DrawToWindow(_handle);
  89. }
  90. public void Deallocate()
  91. {
  92. if (_pBitmap != IntPtr.Zero)
  93. {
  94. Marshal.FreeHGlobal(_pBitmap);
  95. _pBitmap = IntPtr.Zero;
  96. }
  97. }
  98. }
  99. }