using UnityEngine; using System; using System.IO; using System.Windows.Forms; // 모니터 식별 및 스크린 정보 using System.Drawing; // Bitmap 관련 using System.Drawing.Imaging; using System.Runtime.InteropServices; using TMPro; using Unity.VisualScripting; using Application = UnityEngine.Application; using Screen = System.Windows.Forms.Screen; using Graphics = System.Drawing.Graphics; public class TakeScreen : MonoBehaviour { // 캡처할 모니터 인덱스 (2 = 첫번째 모니터) public int selectMonitorIndex = 2; public int takeNumber; int monitorIndex = 0; MONITORINFO selectMonitor; int selectWidth; int selectHeight; [SerializeField] TMP_InputField inputPrefix; [SerializeField] TMP_InputField inputResult; [SerializeField] DirectorySelect directorySelector; // WinAPI 구조체 [StructLayout(LayoutKind.Sequential)] public struct RECT { public int left, top, right, bottom; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct MONITORINFO { public int cbSize; public RECT rcMonitor; public RECT rcWork; public int dwFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szDevice; } // WinAPI 델리게이트 private delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData); // WinAPI 함수 [DllImport("user32.dll")] private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData); [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi); [DllImport("user32.dll")] private static extern IntPtr GetDC(IntPtr hWnd); [DllImport("gdi32.dll")] private static extern IntPtr CreateCompatibleDC(IntPtr hdc); [DllImport("gdi32.dll")] private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height); [DllImport("gdi32.dll")] private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); [DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); [DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr hObject); [DllImport("gdi32.dll")] private static extern bool DeleteDC(IntPtr hdc); [DllImport("user32.dll")] private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); private void Start() { Debug.Log("=== 모든 모니터 정보 ==="); EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorCallback, IntPtr.Zero); } private bool MonitorCallback(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData) { MONITORINFO mi = new MONITORINFO(); mi.cbSize = Marshal.SizeOf(typeof(MONITORINFO)); monitorIndex++; if (GetMonitorInfo(hMonitor, ref mi) && monitorIndex == selectMonitorIndex) { int width = mi.rcMonitor.right - mi.rcMonitor.left; int height = mi.rcMonitor.bottom - mi.rcMonitor.top; bool isPrimary = (mi.dwFlags & 1) != 0; Debug.Log( $"{mi.szDevice} 모니터 \n" + $" - 해상도 : {width} x {height}\n" + $" - 위치 : x = {mi.rcMonitor.left}, y = {mi.rcMonitor.top}\n" + $" - 주 모니터 여부 : {isPrimary}\n" ); selectMonitor = mi; selectWidth = width; selectHeight = height; } return true; // 계속 나머지 모니터 순회 } public void Take() { string fileName = $"{inputPrefix.text}_{string.Format("{0:D2}", takeNumber)}.png"; string savePath = Path.Combine(directorySelector.selectedFolderPath, fileName); Shot(selectMonitor.rcMonitor.left, selectMonitor.rcMonitor.top, selectWidth, selectHeight, savePath); } void Shot(int x, int y, int width, int height, string savePath) { IntPtr desktopDC = GetDC(IntPtr.Zero); IntPtr memoryDC = CreateCompatibleDC(desktopDC); IntPtr bitmap = CreateCompatibleBitmap(desktopDC, width, height); IntPtr oldBitmap = SelectObject(memoryDC, bitmap); BitBlt(memoryDC, 0, 0, width, height, desktopDC, x, y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); using (Bitmap bmp = Image.FromHbitmap(bitmap)) { bmp.Save(savePath, ImageFormat.Png); } // 정리 SelectObject(memoryDC, oldBitmap); DeleteObject(bitmap); DeleteDC(memoryDC); ReleaseDC(desktopDC, memoryDC); inputResult.text = savePath; } }