반응형
프로그램 화면
프로그램은 아래와 같은 순서로 동작하게 끔 만들어졌다.
만들고 있는 프로그램이 있어서 우선 시간관계상 Exception 체크와 기본 동작은 제외하고
정상동작을 가정하여 만들어졌다.
1. [가져오기] 버튼으로 현재 윈도우 창이 있는 프로세스를 가져온다.
2. 콤보박스에서 캡쳐할 프로세스를 선택한다.
3. 영역캡쳐 버튼을 누르면 캡쳐된 화면을 Image 컴포넌트에 뿌려준다.
XAML
<Window x:Class="SimcityBuilditMacro.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SimcityBuilditMacro"
mc:Ignorable="d"
Title="MainWindow" Height="564.7" Width="773.021">
<Grid>
<Image x:Name="imgCapture" Margin="10,10,0,0" HorizontalAlignment="Left" Width="744" Height="484" VerticalAlignment="Top"/>
<ComboBox x:Name="cbxProgramAreaCapture" HorizontalAlignment="Left" Margin="92,499,0,0" VerticalAlignment="Top" Width="582" ItemsSource="{Binding}"/>
<Button x:Name="btnProgramAreaCapture" Content="영역캡쳐" HorizontalAlignment="Left" Margin="679,499,0,0" VerticalAlignment="Top" Width="75" Height="22" RenderTransformOrigin="0.493,0.75" Click="BtnProgramAreaCapture_Click"/>
<Button x:Name="btnProcessRead" Content="가져오기" HorizontalAlignment="Left" Margin="10,499,0,0" VerticalAlignment="Top" Width="75" Height="22" Click="BtnProcessRead_Click"/>
</Grid>
</Window>
CS
WPF 에서는 Process 객체를 통해 Process의 정보를 가져올 수 있다.
하지만, Process를 통해 얻은 Handle 을 Graphics 객체에 바로 사용하면, OutOfMemory 가 발생한다.
그렇다고 MainWindowHandle을 바로 사용한다면, 캡처대상의 윈도우가 활성화 되어 있으면 문제가 없다. 하지만 대상 프로세스가 최소화 되어있다면 ShowWindowAsync 와 SetForegroundWindow 을 써서 활성화를 시켜줘야한다. 이 때는 Thread Sleep을 걸어야하므로 캡처에 쓸데없이 시간이 더 걸리게 된다.
그러는 것보다 아예 User32의 FindWindow 를 통해 Handle을 획득하면 비활성화 상태에서도 캡처가 가능하다.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Media.Imaging;
namespace SimcityBuilditMacro
{
/// <summary>
/// MainWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowRgn(IntPtr hWnd, IntPtr hRgn);
[DllImport("gdi32.dll")]
static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
private Bitmap ProcessCapture(string processName)
{
IntPtr hwnd = FindWindow(null, processName);
Rectangle rc = Rectangle.Empty;
Graphics gfxWin = Graphics.FromHwnd(hwnd);
rc = Rectangle.Round(gfxWin.VisibleClipBounds);
Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
bool succeeded = PrintWindow(hwnd, hdcBitmap, 1);
gfxBmp.ReleaseHdc(hdcBitmap);
if (!succeeded)
{
gfxBmp.FillRectangle(
new SolidBrush(Color.Gray),
new Rectangle(System.Drawing.Point.Empty, bmp.Size));
}
IntPtr hRgn = CreateRectRgn(0, 0, 0, 0);
GetWindowRgn(hwnd, hRgn);
Region region = Region.FromHrgn(hRgn);
if (!region.IsEmpty(gfxBmp))
{
gfxBmp.ExcludeClip(region);
gfxBmp.Clear(Color.Transparent);
}
gfxBmp.Dispose();
//bmp.Save("C:\\SaveFileTest\\test.bmp");
return bmp;
}
private void BtnProcessRead_Click(object sender, RoutedEventArgs e)
{
Process[] prcs = Process.GetProcesses();
List<string> prcsList = new List<string>();
foreach (Process p in prcs)
{
if (p.MainWindowTitle.Equals(""))
{
continue;
}
prcsList.Add(p.MainWindowTitle + "|" + p.Id);
}
cbxProgramAreaCapture.ItemsSource = prcsList;
}
private BitmapImage Bitmap2BitmapImage(Bitmap src)
{
using (MemoryStream memory = new MemoryStream())
{
src.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
memory.Close();
return bitmapimage;
}
}
private void BtnProgramAreaCapture_Click(object sender, RoutedEventArgs e)
{
string prcsName = cbxProgramAreaCapture.SelectedItem.ToString();
imgCapture.Source = Bitmap2BitmapImage(ProcessCapture(prcsName));
}
}
}
반응형
'C - C++ - C# - Form - WPF' 카테고리의 다른 글
[빠르게 보는 WPF] WPF FFME, FFmpeg를 이용한 미디어 / 비디오 / 동영상 재생 (2) | 2019.07.16 |
---|---|
[빠르게 보는 WPF] WPF MediaElement 를 이용한 미디어 / 비디오 / 동영상 재생 (1) | 2019.07.16 |
[빠르게 보는] C# WPF 화면 캡쳐 / 스크린 캡쳐 (0) | 2019.07.09 |
[빠르게 보는] WPF 폴더 선택 다이얼로그 (0) | 2019.07.05 |
C# WPF user32.dll 을 이용하여 전역 키 후킹하기, 핫키 등록하기 / 키 보내기 (2) API를 이용한 예제보기 (2) | 2019.03.21 |
WRITTEN BY
,